Select to view content in your preferred language

4.28 - Popup styling not working

1244
3
Jump to solution
12-19-2023 12:51 AM
michaelkdev
Regular Contributor

How to style the popup component in v4.28? 

In the previous version 4.27, there are a couple of classes to change the styling 

.esri-popup__footer
.esri-popup__header
.esri-popup

But these classes are gone? It's not possible to overwrite the popup's styling? 

popup.png

Is there a way to overwrite these? I would like to set display to none 

.esri-popup__footer { display: none }
.esri-popup__header { display: none }

Thanks

 

 

 

0 Kudos
1 Solution

Accepted Solutions
JoelBennett
MVP Regular Contributor

The short answer is no, you can't override those with page-level CSS like you could previously.  The good news is that it's still possible to hide these elements, using the approach mentioned here.  The rest (which I apologize for) just adds some depth to the overall topic.

Changes to the Popup in 4.28 were fairly radical due to the Calcite integration that took place in that release.  As a result, many of the elements are now in a shadow DOM where they can't be touched by page-level CSS selectors.  This was definitely the biggest problem I wrestled with in the upgrade to 4.28.  To illustrate, popups in our framework (which supports over 100 unique applications) look something like this in 4.27:

427.png

Opinions may vary as to whether that's aesthetically pleasing or not, but it has looked generally the same since the early days of 3.x over 10 years ago, and it matches the theme of the rest of the UI.  Like most windows in a GUI, it has a title bar at the top, and this layout favors the content, making it the most important feature of the popup.  Tools - which are of lesser importance than the content -  are at the bottom, which makes perfect sense.

Enter 4.28, and that all changes to something like this:

428_1.png

  • We now have a pagination bar above the title bar, which is a layout contrary to the accepted standard since the days of Windows 3.1.  Furthermore, the appearance of this bar cannot be changed with page-level CSS.  It also takes up much more space than is necessary in comparison to 4.27 (where it was embedded in the action bar).  As can be seen, less "real" content fits in the popup as a result.  Additionally, depending on where the popup is on the screen, this pagination bar might appear either at the top of the popup or the bottom, giving the user an inconsistent experience.
  • The appearance of the title bar cannot be changed with page-level CSS, like it could for the last decade. (Fortunately, the docking button was easy to hide with a simple configuration parameter.)
  • Tools of lesser importance are now in a more prominent location directly beneath the title bar.  All this makes the user's eyes wander through a bunch of unwanted clutter before getting to the main content.  In addition, the appearance of this action bar cannot be changed with page-level CSS either.

So not only did it no longer fit the look-and-feel of our framework, it just isn't laid out well either.  Should we then overhaul the entire framework's UI just to match this new-and-improved look and layout?  How many hours/weeks/months would that take?  Even if we didn't, what about the numerous hours we'd be spending just updating screenshots within our documentation?

Fortunately, I was able to reproduce enough of the pre-4.28 appearance to be acceptable, but not without a lot of hacking.  For example, this post mentioned previous shows how to programmatically adjust the styling of elements in a shadow DOM, but it has to be done every time the popup opens.  Nonetheless, it works, but I had to add over 100 lines of some of the ugliest code I've written:

var contentFeatureElement = popup.container.querySelector(".esri-features__content-feature");
var headerElement = contentFeatureElement?.shadowRoot.querySelector("calcite-panel")?.shadowRoot?.querySelector("div.header-container");

if (headerElement) {
	//Title bar
	headerElement.style.backgroundImage = "linear-gradient(#19628C, #114562)";
	headerElement.style.backgroundColor = "#19628C";

	//The 'x' (close) button and dock buttons at the right-hand side of the title bar
	var element, elements = headerElement.querySelectorAll(".header-actions calcite-action");

	for (var x = 0; x < elements.length; x++) {
		element = elements[x].shadowRoot?.querySelector("button");

		if (element) {
			element.style.backgroundImage = "linear-gradient(#19628C, #114562)";
			element.style.backgroundColor = "#19628C";
			element.style.color = "#FFFFFF";
		}
	}

	//The action bar (immediately beneath the title bar)
	var calciteActionBar = contentFeatureElement.querySelector("calcite-action-bar");

	if (calciteActionBar) {
		calciteActionBar.style.backgroundColor = "#EEF7FD";
		calciteActionBar.style.borderTop = "1px solid #19628C";
		calciteActionBar.style.borderBottom = "1px solid #19628C";

		//The individual buttons in the action bar
		elements = calciteActionBar.querySelectorAll("calcite-action");

		for (var x = 0; x < elements.length; x++) {
			element = elements[x].shadowRoot?.querySelector("button");

			if (element) {
				element.style.backgroundColor = "#EEF7FD";
				element.style.outline = "none !important";
			}
		}

		//The button for the "More" menu to the right of the other action buttons (if it exists)
		element = calciteActionBar.querySelector("calcite-action-group")?.shadowRoot?.querySelector("calcite-action")?.shadowRoot?.querySelector("button");

		if (element)
			element.style.backgroundColor = "#EEF7FD";
	}

	//The section below is for the pagination bar, which only appears when the popup has multiple features; can appear at the top (header) or the bottom (footer)
	calciteActionBar = popup.container.querySelector(".esri-features__pagination-action-bar");

	if (calciteActionBar) {
		calciteActionBar.style.backgroundColor = "#EEF7FD";

		//The < (Previous) and > (Next) buttons at the left-hand side of the bar
		elements = calciteActionBar.querySelectorAll("calcite-action");

		for (var x = 0; x < elements.length; x++) {
			element = elements[x].shadowRoot?.querySelector("button");

			if (element)
				element.style.backgroundColor = "#EEF7FD";
		}

		//The "Select feature" button at the right-hand side of the bar
		element = calciteActionBar.nextElementSibling.shadowRoot?.querySelector("button");

		if (element)
			element.style.backgroundColor = "#EEF7FD";
	}

	//Check if the popup is in feature selection mode (i.e. when there are multiple features)
	var listItemGroup = popup.container.querySelector("calcite-list-item-group");

	if (listItemGroup) {
		//The table in which the features are listed
		element = listItemGroup.parentNode.shadowRoot?.querySelector("table");

		if (element)
			element.style.border = "1px solid #BECEDE";

		//The title bar of the table
		element = listItemGroup.shadowRoot?.querySelector("tr");

		if (element) {
			element.style.backgroundColor = "#BECEDE";
			element.style.color = "#000066";
		}

		//Individual rows in the table
		elements = listItemGroup.querySelectorAll("calcite-list-item");

		for (var x = 0; x < elements.length; x++) {
			element = elements[x].shadowRoot?.querySelector("tr");

			if (element)
				element.style.backgroundColor = ((x % 2 === 0) ? "#DFECF7" : "#EEF7FD");
		}

		var calcitePanel = popup.container.querySelectorAll("calcite-flow-item")[1]?.shadowRoot?.querySelector("calcite-panel");

		if (calcitePanel) {
			//The title bar
			element = calcitePanel.shadowRoot?.querySelector("div.header-container");

			if (element) {
				element.style.backgroundImage = "linear-gradient(#19628C, #114562)";
				element.style.backgroundColor = "#19628C";
				element.style.color = "#FFFFFF";

				//The title sub-text
				element = element.querySelector(".header-content .description");

				if (element)
					element.style.color = "inherit";
			}

			//The back button in the title bar
			element = calcitePanel.querySelector("calcite-action")?.shadowRoot?.querySelector("button");

			if (element) {
				element.style.backgroundImage = "linear-gradient(#19628C, #114562)";
				element.style.backgroundColor = "#19628C";
				element.style.color = "#FFFFFF";
			}
		}
	} 
}

 

In addition, slight modifications were made to our locally-hosted copy of the API to (1) force the action bar to appear below the content, and (2) force the pagination bar to always appear at the bottom whenever it's visible.  So we now have something like this instead:

428_2.png

As I mentioned earlier, the pagination controls take up way more room than they need, but it is what it is...

View solution in original post

3 Replies
JoelBennett
MVP Regular Contributor

The short answer is no, you can't override those with page-level CSS like you could previously.  The good news is that it's still possible to hide these elements, using the approach mentioned here.  The rest (which I apologize for) just adds some depth to the overall topic.

Changes to the Popup in 4.28 were fairly radical due to the Calcite integration that took place in that release.  As a result, many of the elements are now in a shadow DOM where they can't be touched by page-level CSS selectors.  This was definitely the biggest problem I wrestled with in the upgrade to 4.28.  To illustrate, popups in our framework (which supports over 100 unique applications) look something like this in 4.27:

427.png

Opinions may vary as to whether that's aesthetically pleasing or not, but it has looked generally the same since the early days of 3.x over 10 years ago, and it matches the theme of the rest of the UI.  Like most windows in a GUI, it has a title bar at the top, and this layout favors the content, making it the most important feature of the popup.  Tools - which are of lesser importance than the content -  are at the bottom, which makes perfect sense.

Enter 4.28, and that all changes to something like this:

428_1.png

  • We now have a pagination bar above the title bar, which is a layout contrary to the accepted standard since the days of Windows 3.1.  Furthermore, the appearance of this bar cannot be changed with page-level CSS.  It also takes up much more space than is necessary in comparison to 4.27 (where it was embedded in the action bar).  As can be seen, less "real" content fits in the popup as a result.  Additionally, depending on where the popup is on the screen, this pagination bar might appear either at the top of the popup or the bottom, giving the user an inconsistent experience.
  • The appearance of the title bar cannot be changed with page-level CSS, like it could for the last decade. (Fortunately, the docking button was easy to hide with a simple configuration parameter.)
  • Tools of lesser importance are now in a more prominent location directly beneath the title bar.  All this makes the user's eyes wander through a bunch of unwanted clutter before getting to the main content.  In addition, the appearance of this action bar cannot be changed with page-level CSS either.

So not only did it no longer fit the look-and-feel of our framework, it just isn't laid out well either.  Should we then overhaul the entire framework's UI just to match this new-and-improved look and layout?  How many hours/weeks/months would that take?  Even if we didn't, what about the numerous hours we'd be spending just updating screenshots within our documentation?

Fortunately, I was able to reproduce enough of the pre-4.28 appearance to be acceptable, but not without a lot of hacking.  For example, this post mentioned previous shows how to programmatically adjust the styling of elements in a shadow DOM, but it has to be done every time the popup opens.  Nonetheless, it works, but I had to add over 100 lines of some of the ugliest code I've written:

var contentFeatureElement = popup.container.querySelector(".esri-features__content-feature");
var headerElement = contentFeatureElement?.shadowRoot.querySelector("calcite-panel")?.shadowRoot?.querySelector("div.header-container");

if (headerElement) {
	//Title bar
	headerElement.style.backgroundImage = "linear-gradient(#19628C, #114562)";
	headerElement.style.backgroundColor = "#19628C";

	//The 'x' (close) button and dock buttons at the right-hand side of the title bar
	var element, elements = headerElement.querySelectorAll(".header-actions calcite-action");

	for (var x = 0; x < elements.length; x++) {
		element = elements[x].shadowRoot?.querySelector("button");

		if (element) {
			element.style.backgroundImage = "linear-gradient(#19628C, #114562)";
			element.style.backgroundColor = "#19628C";
			element.style.color = "#FFFFFF";
		}
	}

	//The action bar (immediately beneath the title bar)
	var calciteActionBar = contentFeatureElement.querySelector("calcite-action-bar");

	if (calciteActionBar) {
		calciteActionBar.style.backgroundColor = "#EEF7FD";
		calciteActionBar.style.borderTop = "1px solid #19628C";
		calciteActionBar.style.borderBottom = "1px solid #19628C";

		//The individual buttons in the action bar
		elements = calciteActionBar.querySelectorAll("calcite-action");

		for (var x = 0; x < elements.length; x++) {
			element = elements[x].shadowRoot?.querySelector("button");

			if (element) {
				element.style.backgroundColor = "#EEF7FD";
				element.style.outline = "none !important";
			}
		}

		//The button for the "More" menu to the right of the other action buttons (if it exists)
		element = calciteActionBar.querySelector("calcite-action-group")?.shadowRoot?.querySelector("calcite-action")?.shadowRoot?.querySelector("button");

		if (element)
			element.style.backgroundColor = "#EEF7FD";
	}

	//The section below is for the pagination bar, which only appears when the popup has multiple features; can appear at the top (header) or the bottom (footer)
	calciteActionBar = popup.container.querySelector(".esri-features__pagination-action-bar");

	if (calciteActionBar) {
		calciteActionBar.style.backgroundColor = "#EEF7FD";

		//The < (Previous) and > (Next) buttons at the left-hand side of the bar
		elements = calciteActionBar.querySelectorAll("calcite-action");

		for (var x = 0; x < elements.length; x++) {
			element = elements[x].shadowRoot?.querySelector("button");

			if (element)
				element.style.backgroundColor = "#EEF7FD";
		}

		//The "Select feature" button at the right-hand side of the bar
		element = calciteActionBar.nextElementSibling.shadowRoot?.querySelector("button");

		if (element)
			element.style.backgroundColor = "#EEF7FD";
	}

	//Check if the popup is in feature selection mode (i.e. when there are multiple features)
	var listItemGroup = popup.container.querySelector("calcite-list-item-group");

	if (listItemGroup) {
		//The table in which the features are listed
		element = listItemGroup.parentNode.shadowRoot?.querySelector("table");

		if (element)
			element.style.border = "1px solid #BECEDE";

		//The title bar of the table
		element = listItemGroup.shadowRoot?.querySelector("tr");

		if (element) {
			element.style.backgroundColor = "#BECEDE";
			element.style.color = "#000066";
		}

		//Individual rows in the table
		elements = listItemGroup.querySelectorAll("calcite-list-item");

		for (var x = 0; x < elements.length; x++) {
			element = elements[x].shadowRoot?.querySelector("tr");

			if (element)
				element.style.backgroundColor = ((x % 2 === 0) ? "#DFECF7" : "#EEF7FD");
		}

		var calcitePanel = popup.container.querySelectorAll("calcite-flow-item")[1]?.shadowRoot?.querySelector("calcite-panel");

		if (calcitePanel) {
			//The title bar
			element = calcitePanel.shadowRoot?.querySelector("div.header-container");

			if (element) {
				element.style.backgroundImage = "linear-gradient(#19628C, #114562)";
				element.style.backgroundColor = "#19628C";
				element.style.color = "#FFFFFF";

				//The title sub-text
				element = element.querySelector(".header-content .description");

				if (element)
					element.style.color = "inherit";
			}

			//The back button in the title bar
			element = calcitePanel.querySelector("calcite-action")?.shadowRoot?.querySelector("button");

			if (element) {
				element.style.backgroundImage = "linear-gradient(#19628C, #114562)";
				element.style.backgroundColor = "#19628C";
				element.style.color = "#FFFFFF";
			}
		}
	} 
}

 

In addition, slight modifications were made to our locally-hosted copy of the API to (1) force the action bar to appear below the content, and (2) force the pagination bar to always appear at the bottom whenever it's visible.  So we now have something like this instead:

428_2.png

As I mentioned earlier, the pagination controls take up way more room than they need, but it is what it is...

Marshal
Frequent Contributor

Thanks for all the details and code!  Any chance you could share the modifications to the API that forced pagination bar to always show up at the bottom?

0 Kudos
JoelBennett
MVP Regular Contributor

This behavior can be altered in the file esri/widgets/Popup.js, and fortunately it's very simple.  Here are my notes for 4.28:

Search for: this._featuresWidget.featureNavigationTop=k,{initial:!0}
 
Replace with:  this._featuresWidget.featureNavigationTop=false,{initial:false}
 
 
And here are my notes for 4.29:
 
Search for: this._featuresWidget.featureNavigationTop=v,y.initial
 
Replace with: this._featuresWidget.featureNavigationTop=!1,{initial:!1}