SAP-samples/ui5con-2025-theming-workshop
Starting points for a UI5con 2025 workshop that replace an app's theming logic with a parameterised skeleton CSS built on UI5's theming custom properties, CSS relative colours and container style queries.
Three branches give three flawed starting points, no theming solution, Parameters.get(), and a library.less bundled with the UI5 build, and the task is to replace each with one skeleton CSS driven by the custom properties available in UI5's sap.ui.core library.css since UI5 1.127, using CSS relative colours for lighten and darken functions and container style queries to react to the active theme. A set of OPA5 tests checks the result against a minimum scope covering background colour, opacity and contrast across the sap_horizon themes, and each branch has a -solution counterpart to compare against. A bonus task extends support to UI5 below 1.127 by adding a dependency on @sap-theming/theming-base-content.
Facts
Where it sits
Who is behind it
In the atlas: maintains 222@SAP-samplesmaintainerDominik SchreiberContributes to this
In the atlas: contributes to 3@dominikschreiber1 contributor
What it declares
Every artifact
- Type
- Sample
- Origin
- By SAP
As a sample
- Form
- Workshop or CodeJam material
Connections
Consistent visual identity across controls, including custom themes
Download
README
quoted from SAP-samples/ui5con-2025-theming-workshop under Apache-2.0, readBuild Your Own Themable Product With Theming Parameters And Modern CSS
Description
This repository contains different starting points for the workshop "Build Your Own Themable Product With Theming Parameters And Modern CSS" held by @andreas-roessler, @bhartel, @david-klug-sap and @dominikschreiber at UI5con 2025, on July 8th at SAP in St.Leon-Rot, Germany.
Requirements
Download and Installation
git clone git@github.com:SAP-samples/ui5con-2025-theming-workshop
cd ui5con-2025-theming-workshop
git switch no-theming
# or git switch parameters-get
# or git switch library-less
npm ci
npm start # to start a livereload server
npm test # to test your solution against the minimal scope
Get Started
To pick a starting point, switch to one of the following branches:
no-themingfor a project that does not have a theming solution yetparameters-getfor a project that uses UI5sParameters.get()for theminglibrary-lessfor a project that has a library.less as part of the UI5 distribution build
e.g.
git switch no-theming
The Task
Every starting point tried to make the project themable in a different way. All of them have drawbacks.
Replace the theming logic with a skeleton css that is parameterized with the CSS custom properties that are available in UI5s sap.ui.core library.css since UI5 1.127. Make use of relative colors and container style queries to implement color functions. As a bonus, make the project work with UI5 < 1.127 by adding a dependency to @sap-theming/theming-base-content.
You can track your progress with a set of OPA5 tests:
npm test
If you feel stuck, you can always peek at the solution by adding -solution to your branch, e.g.
git switch no-theming-solution
The minimum solution scope tested by OPA5 tests is
- the top-most petal (
:nth-of-type(5)) has--sapSelectedColoras thebackground-colorin sap_horizon, sap_horizon_dark, sap_horizon_hcb and sap_horizon_hcw - the top-most petal has
opacity: 0.8in sap_horizon and sap_horizon_dark, andopacity: 1in sap_horizon_hcb and sap_horizon_hcw
Other than that, you can be creative with the use of color functions. The sample solution applies the following logic:
- [ ] the
background-colorof every petal- is 10% darker than the previous petal in sap_horizon
- [ ] is 10% lighter than the previous petal in sap_horizon_dark
- stays
--sapSelectedColorin sap_horizon_hcb and sap_horizon_hcw
- [ ] the
border-colorof every petal- is 20% darker than the petals
background-colorin sap_horizon - is 20% lighter than the petals
background-colorin sap_horizon_dark - is the petals
color(text color) in sap_horizon_hcb and sap_horizon_hcw
- is 20% darker than the petals
- the
color(text color) of every petal is a either--sapTextColoror--sapContent_ContrastTextColorbased on contrast against the petals background in sap_horizon, sap_horizon_dark, sap_horizon_hcb and sap_horizon_hcw - all petals have
opacity: 0.8in sap_horizon and sap_horizon_dark, andopacity: 1in sap_horizon_hcb and sap_horizon_hcw
Tools And Techniques
Relative Colors
With CSS Relative Colors (see Using relative colors), you can implement color functions like lighten(), darken() or more. Most of the time it is necessary to use a modern color space, usually oklch() (or oklab()). Now you can apply calc() to the different channel variables of that color:
.color-functions {
--color: #123456;
--lighten-10: oklch(from var(--color) calc(l + 0.1) c h);
--darken-20: oklch(from var(--color) calc(l - 0.2) c h);
/* chroma != saturation, but it's close */
--saturate-30: oklch(from var(--color) l calc(c + 0.3) h);
--desaturate-40: oklch(from var(--color) l calc(c + 0.4) h);
--hue-rotate-50: oklch(from var(--color) l c calc(h + 50deg));
}
Container Style Queries
CSS container queries (see Using container size and style queries) allow to define CSS that applies in specific parts of the page. Container style queries, especially, allow to query the value of CSS properties and custom properties. Themes provide the custom property --sapSapThemeId, to define CSS for specific themes (see Theme-specific CSS for your application):
@container style(--sapSapThemeId: sap_horizon)
or style(--sapSapThemeId: sap_horizon_dark)
or style(--sapSapThemeId: sap_fiori_3)
or style(--sapSapThemeId: sap_fiori_3_dark) {
body {
/* CSS for low-contrast themes */
}
}
Contrast
Until browsers implement contrast-color() properly, we can use a technique described in On compliance vs readability: Generating text colors with CSS to implement background-color-dependent text colors. We define a helper variable, apply the technique to that variable, use a container style query to react in its value, and set the actual value accordingly:
@property --_ContrastColor {
syntax: "<color>";
inherits: true;
initial-value: red;
}
:root {
--Background: #123456;
--TextColor: #f7f8f9;
--_ContrastColor: oklch(from var(--Background) clamp(0, (l / 0.623 - 1) * -infinity, 1) 0 0);
}
@container style(--_ContrastColor: oklch(0 0 0)) {
/* black */
body {
--TextColor: #123456;
}
}
If --Background is theme-dependent (i.e. it is defined in a container style query --sapSapThemeId), the --TextColor can't be defined on the body, it has to be defined inside (because the --Background is defined at the body, which then is the container the style query must match).
Known Issues
No known issues.
How to obtain support
Create an issue in this repository if you find a bug or have questions about the content.
For additional support, ask a question in SAP Community.
Contributing
If you wish to contribute code, offer fixes or improvements, please send a pull request. Due to legal reasons, contributors will be asked to accept a DCO when they create the first pull request to this project. This happens in an automated fashion during the submission process. SAP uses the standard DCO text of the Linux Foundation.
License
Copyright (c) 2025 SAP SE or an SAP affiliate company. All rights reserved. This project is licensed under the Apache Software License, version 2.0 except as noted otherwise in the LICENSE file.
Details
Sources
Sources are graph entities: the same page may back several entries, and an unreachable source flags every row that rests on it.
Compatibility and provenance
Contributors
History in the atlas
- First seen.
For your agent
- Ref
artifact:sap-samples-ui5con-2025-theming-workshop- JSON
- /artifacts/sap-samples-ui5con-2025-theming-workshop.json
- MCP
- Connecting an agent