Last updated Sep 13, 2023

Rate this page:

Preparing your Data Center app for the dark theme

Overview

Theming in Data Center products is supported with the help of design tokens. Design tokens are CSS variables that represent design decisions like elevation, spacing, or — most importantly for the current purpose — colors.

Learn more about design tokens

The public release of dark theme will be rolled out along with one of the upcoming Bitbucket Data Center versions after November 2023. This guide will help you prepare a Data Center app for correct rendering in dark theme.

Supporting dark theme isn’t the only benefit of adopting design tokens in your app. You’ll also achieve better color contrast in light theme and a more consistent and familiar experience within Atlassian products.

Before you begin

We assume that:

Background

Here are some topics relevant to theming in Atlassian products. “What themes should my app support?” is essential. You can skip the others on first reading.

What themes should my app support?

Products will allow switching between three themes: Original, Light, and Dark.

Original theme has the same colors as before the conversion. Teams may want to continue to use this as they wait for all apps in their environment to transition to the design token themes. Additionally, some users are resistant to change, and this option will ease the pain of the transition. As a transitional measure, original theme will be removed at some point after the release of theming.

Light and Dark themes use design tokens. In fact, any given place uses a particular token that has one value in the Light theme and another value in the Dark theme.

The theme switcher will have the fourth option — Match system. It will enable either Light or Dark theme depending on the user’s current settings.

Let’s consider an example:

CSSJavaScript
1
2
.info-field {
  color: var(--ds-text, black);
}
1
2
import { token } from '@atlaskit/tokens';
const infoField = css({
  color: token('color.text', 'black')
})

In this example, --ds-text and 'color.text' represent the same token. Learn more about available tokens

How is theme switching implemented?

In short, Data Center products include the Atlassian User Interface library (AUI). AUI repackages the tokens library from AtlasKit. The tokens library provides definitions for the CSS variables and a function to set the theme.

In general, the details shouldn’t matter to an app developer. What matters is that you define your UI’s colors in terms of the design tokens and have escape hatches to handle more involved scenarios. Loading the correct theme will be handled by the product.

However, if your app can be run in a standalone mode for testing, independent of a product, you might want to implement a theme switcher inside this mode.

If this is the case, you’ll have to decide which path to follow:

What is the current theme?

Sometimes your code will need to know the theme that’s currently enabled. Most commonly, it occurs when there are two different images that represent the same thing (for example, a screenshot of a particular piece of functionality), and we have to pick one depending on the current theme.

During the initial render

Check the data-color-mode attribute on the html element.

CSSJavaScript
1
2
/* Original and Light */
.panel {
  background-image: url(images/bg-light.png);
}
/* Dark */
html[data-color-mode='dark'] .panel {
  background-image: url(images/bg-dark.png);
}
1
2
const colorMode = document.documentElement.getAttribute('data-color-mode')
if (colorMode === null) {
  // Original
} else if (colorMode === 'light') {
  // Light
} else if (colorMode === 'dark') {
  // Dark
}

In some cases, you might also want to check the data-theme attribute on the html element. Its value is the serialized themeState passed to setGlobalTheme, for example, dark:dark light:light shape:shape spacing:spacing. Learn more about the setGlobalTheme method

The right-hand side of each property can be a custom value, so you might want to have a different logic to render something when a particular custom dark theme is enabled, for example, html[data-theme~="custom-dark"] { ... }. However, most likely, you won’t need this functionality.

React to the theme change

In certain cases — for example, when rendering something on a Canvas or replacing an image rendered with JavaScript — you might need to track when a theme is changed.

To do this, use ThemeMutationObserver as in this example:

1
2
import { ThemeMutationObserver } from '@atlaskit/tokens';

const observer = new ThemeMutationObserver((newTheme) => {
  console.log(newTheme.colorMode);
});

observer.observe();
observer.disconnect();

Learn more about the ThemeMutationObserver function

The adaptation process at a glance

The process of adapting your app to Dark theme looks like this:

  1. Include the tokens library.
  2. Make sure the Atlassian (Atlaskit and AUI) components you include are using design tokens.
  3. Make sure colors in your app are using design tokens: in code and in images.
  4. Test your changes.
  5. Introduce lint rules.

Depending on your app’s functionality, some steps won’t be applicable, or there might be more steps in your specific case. We trust your judgment.

Step-by-step instructions for updating your app

Use the tokens library

Add the library to your project:

1
2
yarn add @atlaskit/tokens

You can skip this step if your app’s colors are defined only in CSS files. In this case, you’ll use only the direct var(--ds-text, black) form, which doesn’t require installing the package.

Update Atlassian components

If you include any AtlasKit components, make sure they are on a version published in October 2022 or later.

If you include any AUI components, make sure the AUI version is 9.7.1 or later.

Migrate your app colors: CSS and JavaScript

What we want to achieve

Each color that your app defines should have one of these forms:

  • In CSS files, the var(<CSS syntax>, <fallback>) form:
1
2
.info-field {
  color: var(--ds-text, black);
}
  • In JavaScript or TypeScript files, the token('<JavaScript syntax>', <fallback>) form:
1
2
// Make sure you import the token function
import { token } from '@atlaskit/tokens';
const infoField = css({
  color: token('color.text', 'black')
});

Learn more about available tokens

While it is possible to use the CSS syntax in JavaScript files (for example, const infoField = css({ color: 'var(--ds-text, black)' })), it’s not recommended. The token() form is more future-proof because it warns you if a non-existent token is passed into it.

Step 1: Apply codemods

To kick-start the process, we suggest using the codemods. Learn more about the @atlaskit/codemod-cli package

The package is a general one for all our codemod needs, but the two specific presets (css-to-design-tokens and theme-to-design-tokens) apply to the dark theme migration. They search for hard-coded colors and replace them with token-using expressions.

The replacements are done in place, overwriting the original files. We assume you store your app’s code in a version control system and thus can see the modifications easily and revert them if needed.

Run these commands in your app’s folder:

1
2
# process the CSS-syntax files
npx @atlaskit/codemod-cli -n css-to-design-tokens -e css,scss,less .

# process the JavaScript-syntax files
npx @atlaskit/codemod-cli -n theme-to-design-tokens -p tsx -e ts,tsx,js,jsx .

Step 2: Review changes for proper meanings

Don’t blindly trust the codemods! They apply some heuristics to come up with the suggestions, but they don’t have enough context to be correct every time. The following are some traps to watch for.

There are tokens that have the same value but different names (for example, --ds-text and --ds-icon-warning-inverse are both Neutral1000 in the Light theme). Pick the one that most closely matches the intended use. When in doubt, use the Token picker. Refer to the available tokens page

What if there’s no proper token for the intended meaning?

Check out the Get help section

The codemod treats any objects in JavaScript as potentially CSS-in-JS. If you have objects that happen to have CSS-like properties, such as { color: 'red' }, but those aren’t actually passed to a CSS-in-JS compiler, the codemod will still convert the color expressions. You should revert those changes.

In rare cases, the codemod script won’t be able to propose any substitution and will put the "MISSING_TOKEN" value in the code. In those places, you should pick the right replacement value. The Token picker can also help to make the decision.

Migrate images

If your app uses images, you should do some work for them to look well in both themes. Depending on the image type, the approach will differ. The following approaches are the most common ones.

Review icon fonts or inline SVG

Icons implemented as an icon font most likely won’t require rework. Probably, they already have associated CSS rules that are covered before in the “Migrate your app colors” step.

If you define inline SVG images in JSX files, they will also be effectively handled during the color migration. SVG images that are styled with CSS don't require rework either, because the CSS declarations are changed by codemods.

Migrate images in files

Images (PNG, JPG, SVG, and other types) stored as files are more difficult. For each of these images, you can pick an option:

Migrate dynamically-created images (for example, rendered on Canvas)

Use the colors that fit the current theme. You can find more information in the "Background: What is the current theme?" section.

Test your changes visually

Use your regular procedures for testing visual changes. We assume that you’re using an EAP version of Bitbucket: it comes with a UI toggle to switch between themes.

Switch between themes in Bitbucket Data Center

Switch between themes in Bitbucket Data Center

For all the replaced colors, navigate to the corresponding pages and check if they look fine in all three themes: Original, Light, and Dark.

The following sections include specific suggestions for testing your changes.

Check color contrast

Use a browser extension (like axe DevTools) to check color contrast. If you notice an issue, make sure the replaced color is semantically correct for the place. If it is, let us know, and we will try to fix it. For details on how to contact us, check out the Get help section.

Use AUI testing theme

If you use AUI, you might want to use the testing theme. Check out the AUI dark theme documentation

You can enable it in the console of your browser’s developer tools, and it will replace all design tokens with a single color, making everything that’s not using them stand out. This can catch the cases that the codemods missed.

Introduce lint rules

For better maintainability of your app, add these lint rules into your project to warn about colors that aren’t using a token form:

Your app is updated!

Now your app supports theming:

  • When included in a product that doesn’t have themes yet, the fallback values will ensure it keeps looking as before.
  • When included in a product that has themes, it will look properly in the Original, Light, and Dark themes.

Get help

If you have questions or need help, contact us at The Atlassian Developer Community.

Make sure to include the tag design-tokens.

We’ll do our best to refine the solution based on your feedback.

Rate this page: