NexJ Logo

UI themes and CSS

Themes allow you to match the application to your UI preferences and standards. This is accomplished with theme files and CSS. The recommended approach is to use the capabilities provided in theme files. This currently includes the ability to specify color palettes, background images, and banners.

Themes require some setup in your project to work. If you haven't done so already, follow these instructions.

To enable working with themes, your project must be configured with the following settings.

Update the .project file to identify the Java builder and Java nature for the project. For example:

<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
	<name>projectName</name>
	<comment></comment>
	<projects>
	</projects>
	<buildSpec>
		<buildCommand>
			<name>org.eclipse.jdt.core.javabuilder</name>
			<arguments>
			</arguments>
		</buildCommand>
		<buildCommand>
			<name>com.nexjsystems.nexjstudio.NexJBuilder</name>
			<arguments>
			</arguments>
		</buildCommand>
	</buildSpec>
	<natures>
		<nature>org.eclipse.jdt.core.javanature</nature>
	</natures>
</projectDescription>

Ensure that the mod and src directories exist for your project and then update the .classpath file to include source references these directories. For example:

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
	<classpathentry kind="src" path="mod"/>
	<classpathentry kind="src" path="src"/>
	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
	<classpathentry kind="output" path="bin"/>
</classpath>


Theme files

A theme is simply a property file called mod/themes/<themeName>.theme which contains entries of the form <themeProperty>=<value>. For example, color.back=#EEEEEE. These entries let you override the default look and feel of your application.  If a property is not set in the theme file, the default value is used.

Images used in themes are typically saved into a mod/images/<themeName> folder, so they can be referenced as in the following example:

banner.image.default=url(images/mono/page-nav.png)

Themes can be used either by:

  • Adding a query string parameter to the application URL, for example, <root>/ui/portal?theme=mytheme or <root>/ui/portal?theme=subfolder/mytheme if you organize your themes into folders inside the mod/themes folder.
  • Adding a default theme to the environment file.  Simply add a theme=<themeName> attribute to the root Environment (or Server) element in your environment definition and all users of the application run with that theme, unless overridden in the URL as above.

A good example is the mono theme. So just add ?theme=mono after the url.  Note that if your url has a # path in it, the theme querystring parameter needs to come before the #.


Semantic color properties

Semantic colors used in theme files are based on the Material Design color system, which is organized around color usage and palettes. For more information, see The color system - Material Design.

Colors used in palettes are expected to be used in a variety of areas across the application. If a color is not specified in a theme, its default color value is used.  The following table shows the name of the semantic colors and their default color values. To override the value for a particular semantic color, take the name from below and create an entry in the theme file of the form color.<lower-case-semantic-color-name>=<color-value>. For example, color.back=#EEEEEE.

Although each of the semantic color values may be specified in a theme, according to the specification several of them (error, flash) are not recommended to be changed.


To represent the above colors in a theme, you would create the following color properties in your .theme file:

color.back=#EEEEEE
color.data=#FFFFFF
color.prime=#07589D
color.dark=#013D6C
color.light=#03A9F4
color.link=#07589D
color.accent=#00BFA5
color.action=#01579B
color.flash=#757575
color.media=#B0BEC5
color.notice=#ECEFF1
color.error=#E53935
color.warning=#FFD600
color.info=#39B54A
color.1=#26A69A
color.2=#AB47BC
color.3=#80D8FF
color.4=#FF9100
color.5=#2962FF
color.6=#F06292
color.7=#80CBC4
color.8=#CE93D8
color.9=#B3E5FC
color.10=#FFB74D
color.11=#64B5F6
color.12=#F48FB1

color.flatPrime=#FFF
color.primeCaption=rgba(255,255,255,0.7)
color.primeStrongCaption=#FFF
color.primeTitle=#FFF

Additional properties

  • font - allows you to override the default primary font name, for example, font=Courier

Control properties

These theme properties apply to specific types of AFL controls.

  • page.nav.image - background image for the page navigator. For example, page.nav.image=url(images/mono-nav-closed.png).
  • page.nav.image.open - background image for the open page navigator.  If omitted, the open image will default to the one specified in page.nav.image. For example, page.nav.image.open=url(images/mono-nav-open.png).
  • page.nav.color - color of the hamburger, workspace icon, and workspace text.  Used to improve visibility if the background image is dark, for example, page.nav.color=white.
  • page.nav.title.height - provides the ability to nudge the menu down to make room for a company logo, for example, page.nav.title.height=70px.
  • banner.background - background color of the cards in the banner.
  • banner.badge.background -background color of the badges in the banner. It forms the outline of the badge.
  • banner.tile.comment.color -the color of the subtext inside the banner.
  • gauge.high.color - the color of the gauge in the high area.
  • gauge.low.color - the color of the gauge in the low area.
  • gauge.medium.color - the color of the gauge in the middle area.
  • grid.column.background -the outline color of icons in detail cards. Only affects icons with circular outlines.
  • filter.chip.maxLength - the maximum display width for the content of filter chips (the operator and value), for example, filter.chip.maxLength=280px, which is the default.
  • filter.chip.selected.borderColor - the border color for the currently selected filter chip.
  • schedule.todayCaption.color - the color of today's date in the schedule workspace.
  • tab.hover.color -the color of the text when hovering over a tab.
  • tab.selected.color - the color of the selected tab's text.
  • table.hover.background - the color of a row in the grid during a mouse hover, includes background of the hover toolbar.
  • tooltip.backgroundcolor - background color of the non-native tooltip.
  • tooltip.color - the text color of the non-native tooltip.


Images may be placed in the meta/images folder or in the mod/images folder. The advantage of the mod/images folder is that a server restart is not required as you work on your theme to refresh what you see in your browser. If you are creating images specific to a theme, you should place them in the mod/images/<themeName> folder.

Banner background image properties

Workspace detail pages often have banners. These banners may have default background images configured in the page definition in the model.

Additionally, create and edit dialogs often have header background images.

The background image of all out-of-the-box page banners may be customized with the following properties:

  • banner.image.contact
  • banner.image.company
  • banner.image.user
  • banner.image.opportunity
  • banner.image.service.request
  • banner.image.approval.plan

By setting these properties to an image from your theme, you may replace the out-of-the-box image, for example, banner.opportunity.image=url(images/mono-opportunity-banner.png). You may also eliminate the background image by setting the banner image property to 'none', for example, banner.opportunity.image=none. In this case, the color.prime color will be used. 

Properties for overriding the edit dialog banners are:

  • dialog.banner.image.person
  • dialog.banner.image.company

The property for overriding the menu banner is:

  • menu.banner

For example, you can change the default blue image in the menu to a grey image that matches your color palette.

Example menu.banner theme override

You may use the same image for all banners or have a unique image for each banner. You can use macro substitution and the default.banner.image property, such as in the following code:

banner.image=url(images/mono/page-nav.png)

banner.image.contact=none
banner.image.company=$banner.image
banner.image.user=$banner.image
banner.image.opportunity=$banner.image

Mono theme example

To run the mono theme, simply append your browser URL with the ?theme=mono query string.  Other themes are terminal and training.

Workspace using mono theme

Theme development

Configuring a banner portlet image for use with themes

One of the properties of the banner view is its background image. The image for the banner is set by a DataAction script in your layout that fires the sysBanner event. In the parameters for the sysBanner event, you may provide an image, which could be dynamic based on the type of item you are displaying.

; simple non-dynamic case 
(when (= locator 'selection)
   (@ fireUIEvent : "sysBanner"
      (message
         (: caption (inst'fullNameDetail))
         (: image "image:user.png")
      )
   )
)

If you want to make this configurable through a theme, return a style instead of an image as follows.

(when (= locator 'selection)
   (@ fireUIEvent : "sysBanner"
      (message
         (: caption (inst'title)) 
	     (: style "-banner-mybannertype")
      )
   )
)

Then add a mod/portlet/<ns.BannerPortletName>.css file to your project with a CSS specification like the following:

.-banner-mybannertype {
	background-image: url(images/users.jpg); /*$banner.image.mybannertype*/
}

Here we are tying together the CSS class name banner-mybannertype that we set in the script with a CSS rule that specifies the default background image and a macro that can be set to override the default in a theme file, for example, banner.image.mybannertype.

To override the image in a particular theme, simply specify banner.image.mybannertype to the desired background image for the banner, for example, banner.mybannertype.image=url(images/mytheme/contact.png).

This approach is enabled using a cool feature where you can customize CSS for any portlet by creating a mod/portlet/<ns.portletName>.css file in your project. The colons ":" used to separate namespaces are replaced with periods ".". For example, mda:PersonCreate.portlet would require an associated mod/app/portlet/mda.PersonCreate.css file to load its custom CSS rules.

This approach is very flexible. For example, the following script sets the CSS style (class) based on some condition of the item that the dialog will display.

; or in a case where you want the image to change based on the instance type
(when (= locator 'selection)
   (let ((inst (@ model item))) (@ fireUIEvent : "sysBanner"
      (message
         (: caption (inst'fullNameDetail))
         (:
            style
            (cond
               ((instance? inst UserPerson) "-banner-user")
               ((instance? inst Person) "-banner-person")
               (else "-banner-company")
            )
         )
      )
   )
)

Configuring a dialog portlet image for use with themes

A dialog banner image is usually set in metadata by specifying the image property on the main layout of a dialog. If you want to be able to override this image in themes, you need to inspect the generated markup in your browser to find the name of the layout that hosts the image. You then simply add the following CSS to the mod/dialog/screen/<dialogName>.css file. For example, add the following CSS to the mod/dialog/screen/PersonCreate.css file.

[id='PersonDetail\.mda\:PersonCreate\:1'] .-card-media-image {
	background-image: _ /*$dialog.banner.image.person*/ !important; 
}

In this case, we are providing a theme property of dialog.banner.image.person to override the banner background image of the PersonDetail LayoutRef on the PersonCreate dialog.

Designing a custom palette

Use the Material Design Color Tool at https://material.io/tools/color/ to design a custom palette for your application.

  1. In the Custom tab, pick a primary color and see the dark and light variations of this color.
  2. Pick a secondary color, which will be used as the accent color. You can see how the combination of the two colors and their variations will appear in an application.
  3. Map the semantic colors to the theme file by creating entries as  color.<lower-case-semantic-color-name>=<color-value>.  For example, color.back=#EEEEEE.

Overriding a style in a specific portlet or dialog

You can be very targeted in CSS customizations you make. Simply inspect the classes used in the portlet or dialog you are interested in, then create a file with the following name:

  • mod/app/portlet/<ns1.ns2.PortletName>.css for portlet overrides
  • mod/app/portlet/<ns1.ns2.DialogName>.css to dialog overrides

In the file name, the ns1 and ns2 are any namespaces in the name portlet or dialog name, where the colons ":" are replaced with periods ".". Then create specific CSS rules in that file. The CSS will be loaded and applied when the portlet or dialog is loaded.

Overriding CSS globally

CSS changes may have unknown side effects to UI behavior and may affect how UI tests perform, among other things. This approach is not highly recommended. All modifications of this type should be cataloged, and if a re-occurring pattern emerges, the core product CSS should be instrumented to support the pattern using Theme files. In addition, CSS elements, classes, and ids are not guaranteed to remain the same from release to release.


You may apply global changes to the look and feel through standard CSS.  This is typically done by inspecting the dom with a developer tool in the browser to see what elements, classes, and IDs are available and how they relate to one another.

Enhancements or overrides may be placed in a mod/app/portal.css file in your project.

For instance, the following CSS adds a "roundness" to the filter buttons:


.-tab-tooled-list > A > LI.-caption, .-tab-tooled-list > A > LI.-icon {
   border-radius: 8px;
}

Which changes...

to...