Skip to main content

extendTheme

Tool to extend and modify existing themes.

github
View source code
import { extendTheme } from '@uhg-abyss/web/tools/theme';

The extendTheme tool allows for extending preset themes and allows you to override those themes to fit your design needs. extendTheme is used in conjunction with ThemeProvider and createTheme.

Properties

extendTheme(
baseTheme: CreateThemeReturn,
...overrides: {
/** Theme token overrides */
theme?: DeepPartial<ThemeTokens>;
/** Global CSS style overrides */
css?: Record<string, React.CSSProperties>;
/** Custom CDN URL for brand assets */
brandAssetsCdn?: string;
/** Override the theme name */
themeName?: string;
}[]
): CreateThemeReturn;

Usage

extendTheme takes in a base theme object (from createTheme or another extendTheme) and one or more override objects. The override objects can contain any of the theme properties listed above to modify the base theme. If multiple override objects are provided, they will be merged in the order they are passed in, with later overrides taking precedence over earlier ones. If you do not have access to the base theme object, you can use the ThemeProvider's theme prop as a function to get the current theme object as a parameter and pass it to extendTheme as the base theme.

If the token format is still in a nested JSON structure, you can use flattenTokens to flatten the tokens before passing them to extendTheme.

Overriding theme from createTheme

In this example, we create a base theme using createTheme and then extend it using extendTheme with our custom overrides.

import { ThemeProvider } from '@uhg-abyss/web/ui/ThemeProvider';
import { createTheme, extendTheme } from '@uhg-abyss/web/tools/theme';
const baseTheme = createTheme('uhc');
const themeOverride = {
theme: {
colors: {...},
space: {...},
sizes: {...},
fontSizes: {...},
fonts: {...},
fontWeights: {...},
lineHeights: {...},
letterSpacings: {...},
borderWidths: {...},
radii: {...},
shadows: {...},
opacities: {...},
textDecoration: {...},
textCase: {...},
typography: {...},
},
};
const extendedTheme = extendTheme(baseTheme, themeOverride);
const App = () => {
return (
<ThemeProvider theme={extendedTheme}>
{/* Your application */}
</ThemeProvider>
);
};
() => {
const baseTheme = createTheme('uhc');
const extendedTheme = extendTheme(baseTheme, {
theme: {
colors: {
'core.color.brand.5': '#E7E0FF',
'core.color.brand.10': '#CEC0FF',
'core.color.brand.20': '#D9D0F2',
'core.color.brand.60': '#9E8FE0',
'core.color.brand.80': '#8270D0',
'core.color.brand.100': '#6950C3',
'core.color.brand.120': '#2F1783',
},
},
});
return (
<React.Fragment>
<Layout.Stack grow space={16}>
<ThemeProvider theme={baseTheme}>
<Button>Original Button</Button>
</ThemeProvider>
<ThemeProvider theme={extendedTheme}>
<Button>Custom Button</Button>
</ThemeProvider>
</Layout.Stack>
</React.Fragment>
);
};

Overriding theme from ThemeProvider

In this example, we use the ThemeProvider's theme prop as a function to get the current theme and extend it with our custom overrides using extendTheme.

import { ThemeProvider } from '@uhg-abyss/web/ui/ThemeProvider';
import { createTheme, extendTheme } from '@uhg-abyss/web/tools/theme';
const themeOverride = {
theme: {
colors: {
'web.semantic.color.surface.container.tertiary': '#F0F0F0',
},
},
};
const App = () => {
return (
<ThemeProvider
theme={(currentTheme) => extendTheme(currentTheme, themeOverride)}
>
{/* Your application */}
</ThemeProvider>
);
};
<React.Fragment>
<Layout.Stack grow space={16}>
<Button>Original Button</Button>
<ThemeProvider
theme={(currentTheme) =>
extendTheme(currentTheme, {
theme: {
colors: {
'core.color.brand.5': '#E7E0FF',
'core.color.brand.10': '#CEC0FF',
'core.color.brand.20': '#D9D0F2',
'core.color.brand.60': '#9E8FE0',
'core.color.brand.80': '#8270D0',
'core.color.brand.100': '#6950C3',
'core.color.brand.120': '#2F1783',
},
},
})
}
>
<Button>Custom Button</Button>
</ThemeProvider>
</Layout.Stack>
</React.Fragment>;

Extending with flattened tokens

If your tokens are in nested JSON format (e.g., from Figma Tokens Studio), use flattenTokens to flatten the tokens before passing them to extendTheme.

import { flattenTokens, extendTheme } from '@uhg-abyss/web/tools/theme';
import customTokens from './tokens/custom-colors.json';
const flattenedTokens = flattenTokens(customTokens);
const App = () => {
return (
<ThemeProvider
theme={(currentTheme) =>
extendTheme(currentTheme, {
theme: flattenedTokens,
})
}
>
{/* Your application */}
</ThemeProvider>
);
};

Multiple overrides

When you need to compose overrides from different sources (e.g., a brand override + a feature-specific override), pass them as separate arguments. They are merged left-to-right, with later overrides taking precedence.

import { createTheme, extendTheme } from '@uhg-abyss/web/tools/theme';
const baseTheme = createTheme('uhc');
const brandOverride = {
theme: {
colors: {
'core.color.brand.100': '#003DA5',
'core.color.brand.80': '#002D7A',
'core.color.brand.120': '#001F52',
},
},
};
const featureOverride = {
theme: {
colors: {
'web.semantic.color.surface.container.tertiary': '#F5F5F5',
},
space: {
'core.spacing.200': '20px',
},
},
};
// brand + feature overrides merged (feature wins on conflicts)
const extendedTheme = extendTheme(baseTheme, brandOverride, featureOverride);

Multiple nesting levels

Themes can be extended multiple levels deep. Each level inherits all customizations from its ancestors while adding its own. In this example, each level changes a different visual property — color, background, and shape — so the cumulative inheritance is immediately visible.

Table of Contents