This guide will help you migrate from old theme variables to the new theme variables.
Step 1: Automatically migrate to the new theme variables
We provide an ESLint plugin to help you quickly migrate the basic variables. Run the following command:
npm run lint:file -- <path to lint> --fixThe automatic migration mainly replaces old variables with reference variables. These reference variables are not semantic and cannot fully respond to theme settings. For example:
// Old variable
theme.colors.palette.light[300]
// After auto replacement
theme.ref.palette.neutral[400]Although this completes the migration, if the variable is used for something like a panel background, you should manually replace it with the appropriate system variable for semantic clarity, such as:
theme.sys.color.surface.paperIn short, the auto migration is just the starting point. You still need to manually replace reference variables with semantic system variables based on their actual usage. Please refer to the system variable documentation for details.
Step 2: Manually replacing non-semantic variables
After automatic migration, all old theme variables will be replaced with new ones. This ensures Widgets/components can run under the new theme system. However, note that automatic migration only replaces old variables with non-semantic reference variables. At this stage, your Widget will not correctly respond to theme changes.
Next, we'll walk through how to upgrade Widget UI to semantic theme variables.
Auto-marking non-semantic variables (optional)
To help identify non-semantic variables, you can use our ESLint plugin. If you prefer manual inspection, skip this step.
Focus on the following types of variables:
- Reference palette variables: All palette references are non-semantic and must be replaced.
- System color variables: Replace with semantic alternatives whenever possible. For example:
- ❌ Do not use
theme.sys.color.primary.mainfor a selected tab color - ✅ Use
theme.sys.color.action.selected.defaultinstead
- ❌ Do not use
ESLint rule configuration
- Open
client/eslint.config.jsand find the following rules:
jimu-theme/no-ref-palette: ['error', ...]
jimu-theme/no-improperly-color: ['warn', ...]jimu-theme/no-ref-palette: Flags all palette references (must replace).jimu-theme/no-improperly-color: Flags improper system color usage (replace if appropriate).
- In the
filesconfig, add the Widget/component paths (prioritize runtime UI and core components). - Run the command to scan and highlight variables to be replaced:
npm run lint:file -- <path-to-lint>Background & text colors
The new theme uses the theme.sys.color.surface variable set to unify background and text styling.
Main layers include:
- Background: Page background
- Paper: Panels, widgets, cards, dialogs
- Overlay: Top-level containers or grouped UI blocks inside Paper
Each layer provides two text colors:
- Text: Default text/icon color
- Hint: Lighter, secondary text color
Using Paper as a widget container
Widgets should use the Paper component as their container:
const Widget = () => {
return <Paper variant="flat" shape="none" className="jimu-widget widget-xxx">...</Paper>
}Default styles:
- Background:
theme.sys.color.surface.paper - Text:
theme.sys.color.surface.paperText
For lighter text, use surface.paper, preferably via <Typography color="paper:
<Typography color="paperHint">Secondary text</Typography>Other options:
- Border:
<Paper variant="outlined" /> - BorderRadius:
<Paper shape="shape1" /(default is> shape2) - Transparent background:
<Paper variant="flat" transparent />
Popup widget content containers
For popup widgets triggered by icons (e.g., Filter widget), wrap content inside Paper with transparent={true}:
const Widget = () => {
const buttonRef = React.useRef(null)
const [open, setOpen] = React.useState(false)
return (
<div className="jimu-widget widget-xxx">
<Button ref={buttonRef} variant="text" icon={true} onClick={() => setOpen(!open)}>
<FilterOutlined />
</Button>
<Popper reference={buttonRef.current} open={open}>
<Paper variant="outlined" transparent={true}>
...
</Paper>
</Popper>
</div>
)
}Component guidelines inside Paper
-
Text or icon buttons without background: Use the text button
Use dark colors for code blocks Copy <Button variant="text" color="inherit">...</Button> -
Components with background: Use normally
Overlay blocks inside Paper
When Paper needs to hold an additional backgrounded UI block, use <Surface level="overlay" /.
Surface maps directly to the surface color system with three levels:background, paper, overlay
Default styles for <Surface level="overlay" /:
- Background:
theme.sys.color.surface.overlay - Text:
theme.sys.color.surface.overlayText
For lighter text inside Overlay, use surface.overlay:
<Typography color="overlayHint">...</Typography>Brand & functional colors
Beyond neutral backgrounds and text, use brand colors (e.g., primary) and functional colors (error, warning, success).
Each color includes:
main: Default colorlight/dark: Variations for hover, borders, etc.text: Text/icon color on that background
Examples:
- Primary button → background:
primary.main, hover:primary.dark, text:primary.text
- Error alert → border:
error.dark, text:error.main
Interactive elements
We prefer using UI component(Button, Tab, Checkbox, etc) rather than theme tokens to manage interactive elements within widgets. But if you really need to use the theme tokens, please use the tokens below:
- Default state (buttons, pagination):
theme.sys.color.action.defaulttheme.sys.color.action.hovertheme.sys.color.action.text
- Disabled state:
- Background:
theme.sys.color.action.disabled.default - Text:
theme.sys.color.action.disabled.text
- Background:
- Selected state (Tab, Radio, Checkbox, Switch):
theme.sys.color.action.selected.defaulttheme.sys.color.action.selected.text
- Link state:
theme.sys.color.action.link.defaulttheme.sys.color.action.link.hovertheme.sys.color.action.link.visited
Borders & Dividers
Common divider color in widgets: theme.sys.color.divider.secondary
Shape (border radius)
The border radius of the widget container (Paper) defaults to shape2 (theme.sys.shape.shape2).
If the widget's panel is relatively small, use shape1 instead.
const Widget = () => {
return <Paper className="jimu-widget widget-xxx" shape="shape1">...</Paper>
}Typography
The typography system enhances readability and hierarchy:
- H1-H3: Prominent headings/numbers
- H4-H6: Compact emphasis on small screens
- Title: Subtle, moderately emphasized text
- Body: Main text content
- Input: Text in inputs and selectors
- Label: Buttons, form labels, navigation items
Typography variables are encapsulated in the Typography component.
- Use
variantto pick a level (e.g.,variant="title2"→theme.sys.typography.title). - Default color inherits from the parent container (
color="inherit"). - You may specify
surfacetext colors, e.g.:
<Typography variant="body" color="paperHint">Some hint text</Typography>Common patterns:
- In widget UIs, the most common elements are titles, body text, and labels.
- For tables, text inside cells should use body
- In cards, titles are usually title1, and the body uses body
- In lists, the body text is also typically body
-
For more complex hierarchical forms, such as a widget's settings page, multiple levels of titles may be used
ArcGIS Maps SDK components
The framework has handled the theme token mapping between the Jimu theme and Calcite theme, this means you don't need to care about the style of the Calcite components. However, if you don't use the Calcite components and Jimu components, for example, if you use a ArcGIS Maps SDK web component, you may need to override the tokens in your widget if it does not fit the theme.
Step 3: Test theme adaptation
Testing in the new theme
- Create a new app and add your widget to the page.
- Open the Theme settings page and check the following:
-
Primary / Function colors Change the primary and function colors to confirm the widget UI responds correctly.
-
Neutral colors In the design of Jimu Theme, Neutral is always gray. When customizing the neutral color, only about 10% of the selected color is blended into the neutral. As a result, the change is subtle and may not be immediately noticeable, so please check carefully.
-
Dark mode The new theme supports both light and dark modes. You can try it by enabling "Dark mode (test)" in the theme settings.
Note: This option is for testing purposes only and will be removed before the official release.
-
Background section
- Change the Secondary background and check whether the widget background and text colors update correctly.
- If the widget includes grouped UI elements with backgrounds, change the Tertiary background and confirm correct behavior.
-
Action elements section
- Change the Action default / text colors to verify interactive elements respond correctly.
- Change the Action selected / text colors to verify selected elements respond correctly.
-
Typography tab Modify heading and body fonts to confirm widget text responds correctly.
-
More tab
- Adjust Border radius to confirm rounding applies correctly to the widget and other elements.
- Open the Components section, change each option, and confirm correct behavior.
-