Skip to content

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:

Use dark colors for code blocksCopy
1
npm run lint:file -- <path to lint> --fix

The automatic migration mainly replaces old variables with reference variables. These reference variables are not semantic and cannot fully respond to theme settings. For example:

Use dark colors for code blocksCopy
1
2
3
4
5
// 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:

Use dark colors for code blocksCopy
1
theme.sys.color.surface.paper

In 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.main for a selected tab color
    • ✅ Use theme.sys.color.action.selected.default instead

ESLint rule configuration

  1. Open client/eslint.config.js and find the following rules:
Use dark colors for code blocksCopy
1
2
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).
  1. In the files config, add the Widget/component paths (prioritize runtime UI and core components).
  2. Run the command to scan and highlight variables to be replaced:
Use dark colors for code blocksCopy
1
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:

Use dark colors for code blocksCopy
1
2
3
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.paperHint, preferably via <Typography color="paperHint" />:

Use dark colors for code blocksCopy
1
<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 />
Theme guide surface text

For popup widgets triggered by icons (e.g., Filter widget), wrap content inside Paper with transparent={true}:

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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>
  )
}
Theme guide surface popup

Component guidelines inside Paper

  • Text or icon buttons without background: Use the text button

    Use dark colors for code blocksCopy
    1
    <Button variant="text" color="inherit">...</Button>
  • Components with background: Use normally

Theme guide surface components

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.overlayHint:

Use dark colors for code blocksCopy
1
<Typography color="overlayHint">...</Typography>
Theme guide surface overlay

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 color
  • light / 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
Theme guide brand color
  • Error alert → border: error.dark, text: error.main
Theme guide error color

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.default
    • theme.sys.color.action.hover
    • theme.sys.color.action.text
  • Disabled state:
    • Background: theme.sys.color.action.disabled.default
    • Text: theme.sys.color.action.disabled.text
  • Selected state (Tab, Radio, Checkbox, Switch):
    • theme.sys.color.action.selected.default
    • theme.sys.color.action.selected.text
  • Link state:
    • theme.sys.color.action.link.default
    • theme.sys.color.action.link.hover
    • theme.sys.color.action.link.visited

Borders & Dividers

Common divider color in widgets: theme.sys.color.divider.secondary

Theme guide divider

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.

Use dark colors for code blocksCopy
1
2
3
const Widget = () => {
  return <Paper className="jimu-widget widget-xxx" shape="shape1">...</Paper>
}
Theme guide shape

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 variant to pick a level (e.g., variant="title2"theme.sys.typography.title).
  • Default color inherits from the parent container (color="inherit").
  • You may specify surface text colors, e.g.:
Use dark colors for code blocksCopy
1
<Typography variant="body" color="paperHint">Some hint text</Typography>

Common patterns:

  • In widget UIs, the most common elements are titles, body text, and labels.
Theme guide typography normal
  • For tables, text inside cells should use body
Theme guide typography table
  • In cards, titles are usually title1, and the body uses body
Theme guide typography card
  • In lists, the body text is also typically body
Theme guide typography list
  • For more complex hierarchical forms, such as a widget's settings page, multiple levels of titles may be used

    Theme guide typography titles

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

  1. Create a new app and add your widget to the page.
  2. 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.

References

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.