Instant theme-ability with theming-base-content

Fiori is SAPs award-winning UX approach. Application frameworks like SAP UI5 or Web Dynpro ABAP as well as component libraries like UI5 Web Components or Fundamental Library Styles offer rich features to deliver this UX to customers. With the open-source theming-base-content you have the possibility to create a browser-based Fiori experience in your established technology stack – from fully-fledged Svelte applications to bare-metal HTML pages.

This post walks through the consumption of @sap-theming/theming-base-content, the open-source npm package that contains font-, metric- and color-definitions of Belize, Quartz and Horizon, the Fiori themes of SAP. We will

  • consume the npm package,
  • use the provided css variables,
  • build our own component with them, and
  • implement switching themes with a sap-theme URL parameter.

Consuming the npm package

@sap-theming/theming-base-content is available in the public npm registry, you can simply add it to your project with

npm install --save @sap-theming/theming-base-content

Alternatively you can always grab theming-content-base as a zip file from its project releases on  github.com.

For this post we will make use of the unpkg.com service that allows to reference npm packages directly via URL. So, considering a minimal HTML example, we just add the following:

<link rel="stylesheet" href="https://unpkg.com/@sap-theming/theming-base-content/content/Base/baseLib/sap_horizon/css_variables.css">

This loads the css variable definitions of all theming parameters of sap_horizon, which is the “Morning Horizon for SAP Fiori” theme. From now on we can simply use them, e.g. like color: var(–sapTextColor). More on that later.

A few words on the structure of the project: inside /content we find a whole “theming repository”,

  • containing “frameworks“, in our case Base, but in other theming repositories you might encounter e.g. UI5 or UR as well,
  • which contain “libraries“, in our case baseLib, but e.g. in case of UI5 this might be sap/ui/core/themes,
  • which contain “themes“, in our case sap_horizon, but these might be other SAP themes (like sap_belize) as well as custom themes created with the UI theme designer,
  • which finally contain “files“, that are actually resources – we’re interested in css_variables.css, but e.g. UI5 most often loads a library.css file from here.

So the full path inside the npm package is /content/<framework>/<library>/<theme>/<file>, in our case /content/Base/baseLib/sap_horizon/css_variables.css. Now that we know that we can start using the provided css variables.

Using the provided css variables

The theming-base-content provides the theming parameters as CSS custom properties. Each theme contains a css_variables.css file with all parameter definitions (in addition to a less_variables.less file with the parameters in less notation and a sass_variables.scss file for sass notation).

As we already loaded the css_variables.css in our HTML example we can directly start using them:

<link rel="stylesheet" href="https://unpkg.com/@sap-theming/theming-base-content/content/Base/baseLib/sap_horizon/css_variables.css">
<body style="background-color: var(--sapBackgroundColor)"></body>

Here we use sapBackgroundColor for the background of the whole body of the page. In practice, you will avoid setting CSS in style attributes directly, and create your own library of CSS classes.

Building a small component

For the sake of this post we will try to make all <button> elements behave like Fiori Buttons. Note that you could simply use the CSS class fd-button of the Fundamental Library Styles or the <ui5-button> of the UI5 Web Components, but that would also leave a larger dependency footprint on your application.

First, we skim the css_variables.css for theming parameters fitting our purpose. This quickly leads us to parameters of the sapButton namespace. Most of them are self-explanatory, and we’ll stick with them. We’ll also stick to “standard buttons”, leaving out flavors like “accept”, “reject” or similar.

Our CSS quickly becomes the following:

<link rel="stylesheet" href="https://unpkg.com/@sap-theming/theming-base-content/content/Base/baseLib/sap_horizon/css_variables.css">
<style> /* define the 72 @font-face */ @font-face { font-family: '72'; /* currently, fonts have to be referenced absolutely (although there is e.g. --sapFontUrl_72_Regular_woff2, because the gets rewritten to the wrong value) */ src: url('https://unpkg.com/@sap-theming/theming-base-content/content/Base/baseLib/baseTheme/fonts/72-Regular.woff2') format('woff2'); } button { /* reset user-agent button styles */ appearance: none; display: inline-flex; justify-content: center; align-items: center; /* a button should position itself nicely in lines of ${sapElement_LineHeight} height */ margin: calc((var(--sapElement_LineHeight) - var(--sapElement_Height)) / 2) 0; /* the height of the button should be ${sapElement_Height} */ height: var(--sapElement_Height); /* horizontal padding does not exist as a metric parameter (yet?) */ padding: 0 .75rem; /* now we can start mapping parameters of the sapButton namespace */ border: var(--sapButton_BorderWidth) solid var(--sapButton_BorderColor); border-radius: var(--sapButton_BorderCornerRadius); /* _Background and _TextColor almost always exist together, to ensure contrast between them */ background-color: var(--sapButton_Background); color: var(--sapButton_TextColor); font-family: var(--sapFontFamily); font-size: var(--sapFontSize); cursor: pointer; } button:hover { border-color: var(--sapButton_Hover_BorderColor); background-color: var(--sapButton_Hover_Background); color: var(--sapButton_Hover_TextColor); box-shadow: var(--sapContent_Interaction_Shadow); } button:active { border-color: var(--sapButton_Active_BorderColor); background-color: var(--sapButton_Active_Background); color: var(--sapButton_Active_TextColor); } button:focus-visible { /* focus is defined in the sapContent_Focus namespace */ outline: var(--sapContent_FocusWidth) var(--sapContent_FocusStyle) var(--sapContent_FocusColor); /* the focus outline is moved inside the button to make it work inside elements with overflow:hidden */ outline-offset: calc(-1 * (var(--sapContent_FocusWidth) + var(--sapButton_BorderWidth)) - 1px); }
</style>
<button>Standard Button</button>

With that we have a drop-in Fiori styling for all <button> elements. The nice thing is that by switching the theme in the theming-base-content (e.g. from sap_horizon to sap_fiori_3, which is the technical identifier of the SAP Quartz theme) we get a different Fiori UX without touching our component library at all. How that can be done at runtime is shown next.

Switching themes

All it needs to switch between themes is loading a different css_variables.css. We’ll implement the ThemeID-part of the sap-theme URL-parameter to achieve this:

<link rel="stylesheet" id="theme">
<style>/* … see previous example … */</style>
<button>Standard Button</button>
<script>
const allowlist = ['sap_horizon', 'sap_fiori_3', 'sap_fiori_3_dark', 'sap_belize', 'sap_belize_deep'];
// search for ?sap-theme=… or &sap-theme=… in the URL
const [, sapTheme] = /[\?\&]sap-theme=([^\&]+)/.exec(location.search) || [];
// sanitize input, fall back to sap_horizon
const theme = allowlist.includes(sapTheme) ? sapTheme : 'sap_horizon'; document.getElementById('theme').href = `https://unpkg.com/@sap-theming/theming-base-content/content/Base/baseLib/${theme}/css_variables.css`
</script>

Now we are able to open our HTML with as URL parameter ?sap-theme=sap_fiori_3 and see our button in the SAP Quartz theme instead.

Recap

What have we achieved?

  • Referenced the open-source theming-base-content via npm, as zip or in the browser.
  • Used theming parameters in our own CSS.
  • Made all <button> elements look like Fiori Buttons.
  • Switched between themes with the sap-theme parameter.

Next steps

Let your own creativity fly. As a start you could

  • implement Accept/Reject buttons based on an attribute (e.g. <button accept></button>) or class (<button class=”accept”></button>) selector, or
  • implement the full sap-theme parameter that also allows to load themes from a different theme repository with @ in the parameter value (i.e. ?sap-theme=sap_horizon@https://my-theme-repository.com should set the link href to https://my-theme-repository.com/Base/baseLib/sap_horizon/css_variables.css).

So: let’s get into a discussion.

  • Have you already used the theming-base-content in your projects? Let me know your findings in the comments.
  • Have you considered using the theming-base-content directly but decided against it? Write a comment what prevented you from using it.
  • Have you heard of the theming-content for the first time? Use it and leave a comment how it went.