Theming
Theming allows for the customization of specific visual attributes across the product interface.
Theming allows for the customization of specific visual attributes across the product interface.
Cloudscape currently offers a default theme, which you can use for your own applications or products. Theming is used for modification of some visual aspects of the UI to meet product-specific needs.
Theming is applied to foundational elements and reflected in all elements provided by the system that uses its foundation. To promote a consistent and unified brand experience for users, Cloudscape doesn’t currently support theming individual instances of components.
Theming is achieved by changing specific design tokens. There are three categories of design tokens: typography, colors, and border radii. Changes are applied globally across the UI and are reflected in all components which use the system's foundation.
Theming can be used to better reflect a brand identity or meet other industry-specific needs.
Changing color values of brand or common UI related tokens.
Changing the typeface of your product.
Changing the border radius of elements. For example: containers, form elements, alerts, and notifications.
Applying visual changes globally across a product.
Applying visual changes to predefined visual contexts.
Color, typography, and border radius tokens that can be themed are marked as themeable in the tokens table. Data visualization color tokens that are themeable can be found in the respective color palette tables. To experiment with theming, you can modify the values of themeable tokens in our demos by choosing Theme on the right of the top navigation.
Creating new design tokens.
Changing spacing, motion, iconography, grid, or other foundational elements not listed above.
Making visual changes to instances of components and not others.
If you require any of these features, open a feature request with us and share detailed use cases and product requirements.
Cloudscape components are built according to accessibility guidelines and industry best practices, such as semantic markup and use of appropriate ARIA attributes. If you modify colors, ensure that you employ proper color contrast checks.
Cloudscape offers a dark mode. Each color-related design token has a light mode and a dark mode value. If you don't specify a dark mode custom value, it will automatically apply the default one offered by the system. To maintain correlation and brand identity in themed interfaces, we recommend that you specify the dark mode alternative for modified color tokens.
When a visual context uses a visual-context-specific value for a design token, this value is not overridden by global theming changes to the design token. To theme the design token in a visual context, you need to explicitly define a context-scoped set of overrides in your theme.
Context ID | Description |
|---|---|
top-navigation | Used for the Top navigation component and its content. |
header | Used for the dark header area of the page (high contrast header variant of app layout andcontent layout). |
flashbar | Used for the Flashbar component and its content. |
alert | Used for the Alert component and its content. |
Cloudscape offers two approaches to implement theming:
Build-time theming: you can create a package that contains all Cloudscape components with your custom theme.
Runtime theming: you can apply a theme in the browser, on top of the default Cloudscape components.
Below you will find more details about each approach, and recommendations on when to use each based on your use case.
Both approaches require you to define a theme as input parameter.
You can define a theme by providing custom values for themeable design tokens. There are three categories of themeable tokens: typography, color, and border radius.
The custom values you set for typography tokens (such as fontFamilyBase) are applied globally in the entire application, including visual contexts. When setting custom values for font families, ensure that you also provide the corresponding font assets.
For example, a theme with a new value for fontFamilyBase looks like the following:
const theme = {
tokens: {
fontFamilyBase: "'Helvetica Neue', Roboto, Arial, sans-serif",
},
};
The values you set for border radius tokens (such as borderRadiusButton) are applied globally across the entire UI, including visual contexts.
For example, a theme with a new value for borderRadiusButton looks like the following:
const theme = {
tokens: {
borderRadiusButton: "4px",
},
};
You can set custom values for color tokens globally, and for each visual context. If you don't explicitly specify a custom value for a visual context, the default Cloudscape value will be applied.
You can also specify a value for both light and dark mode. Here is an example:
const theme = {
tokens: {
// Values are applied globally, except for visual contexts
colorBackgroundLayoutMain: {
// Specify value for light and dark mode
light: 'white',
dark: 'blue'
}
// Shorter syntax to apply the same value for both light and dark mode
colorTextAccent: '#0073bb',
},
contexts: {
// Values for visual contexts. Unless specified, default values will be applied
'top-navigation': {
tokens: {
colorTextAccent: '#44b9d6',
},
},
header: {...}
flashbar: {...}
alert: {...}
},
};
You can theme Cloudscape components by generating a stylesheet with your custom theme as part of your build process, and include it in your application on top of the default Cloudscape styles.
Use the generateThemeStylesheet function from the theming module of the @cloudscape-design/components-themeable package as part of your build process. You must provide a selector.
import { join } from 'path';
import { writeFileSync } from 'fs';
import { generateThemeStylesheet } from '@cloudscape-design/components-themeable/theming';
const theme = {...};
const stylesheet = generateThemeStylesheet({ theme, selector: "body" });
writeFileSync(join(__dirname, './app-theme.css'), stylesheet);
You can now import your generated CSS file in your application so that it loads after the default Cloudscape styles. The imported theme will override the theme for all Cloudscape components rendered under the elements targeted by the selector. The selector can be scoped to "body" or any specific element where the theme should be scoped to.
The generateThemeStylesheet function is also available during runtime from the theming module of the @cloudscape-design/components-themeable module. This lets you generate and inject a stylesheet during runtime to override Cloudscape styles. You must provide a selector.
import { Theme, generateThemeStylesheet } from '@cloudscape-design/components/theming';
const theme: Theme = {...};
const styles = generateThemeStylesheet({ theme, selector: "body" });
const stylesheet = new CSSStyleSheet();
stylesheet.replaceSync(styles);
document.adoptedStyleSheets.push(stylesheet);
Themes can also be applied during runtime using the applyTheme function. This automatically creates an inline <style> element and attaches it to the document. When using applyTheme, make sure your Content Security Policy supports inline stylesheets by adding Content-Security-Policy: style-src: 'self' 'unsafe-inline';.
import { Theme, applyTheme } from '@cloudscape-design/components/theming';
const theme: Theme = {...};
const { reset } = applyTheme({ theme, selector: "body" });
// Use the reset method to remove the custom theme
Refer to the demo pages and the theme switcher in the top of the navigation bar to try out runtime theming.
We recommend build-time theming because:
It offers better performance: runtime theming requires to bundle a large file that contains default theme definitions, so that updated styles can be generated. Generating styles is also CPU-heavy, so generating runtime styles can block the main thread.
It provides better support for server-side rendering (SSR) and server-side generation (SSG): for SSR or SSG applications, runtime theming is applied only after hydration, providing a sub-optimal user experience as the user sees the non-themed application first.
Use runtime theming only if your application themes must be dynamically defined or updated for each customer on the frontend.