grafana/contribute/style-guides/themes.md
Jack Westbrook d282b7a6f8
Grafana UI: Make it possible to bundle package with plugins (#76191)
* moved themecontext to data

* chore(grafana-ui): re-export ThemeContext from grafana/data for backwards compatibility

* Moved icon bundling to core.

* feat(plugins): share react-inlinesvg with plugins for grafana/ui bundling

* chore(codeowners): add generate-icon-bundle.js to file

* chore(storybook): update path to iconBundle file for theme

* feat(plugins): share i18n dependency via systemjs

* Make sure that icon bundle is initialized for tests.

* Removed comment.

* added tests for icon root.

* Removing the need of having an init variable.

* feat(grafana-ui): add icon svgs to bundle for projects that don't rely on grafana

---------

Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
2023-10-13 14:11:41 +02:00

6.9 KiB

Theming Grafana

Overview

Themes are implemented in Typescript. That's because our goal is to share variables between Grafana TypeScript and Sass code. Theme definitions are located in the following files:

Usage

This section provides usage guidelines.

Using themes in React components

Here's how to use Grafana themes in React components.

useStyles2 hook

useStyles2 memoizes the function and provides access to the theme.

import React, { FC } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
import { css } from '@emotion/css';

function Foo(props: FooProps) {
  const styles = useStyles2(getStyles);
  // Use styles with className
}

const getStyles = (theme: GrafanaTheme2) =>
  css({
    padding: theme.spacing(1, 2),
  });

Get the theme object

import React, { FC } from 'react';
import { useTheme2 } from '@grafana/ui';

const Foo: FC<FooProps> = () => {
  const theme = useTheme2();

  // Your component has access to the theme variables now
};

Picking the right variable

The rich color object and the state colors

The theme.colors object has 6 rich color objects for primary, secondary, info, success, warning and error. These all have the same sub colors that have different use cases.

Property When to use
main For backgrounds
shade For hover highlight
text For text color
border For borders, currently always the same as text color
contrastText Text color to use for text placed on top of the main color

Example use cases:

  • Want a red background? Use theme.colors.error.main
  • Want green text? Use theme.colors.success.text
  • Want text to be visible when placed inside a background that uses theme.colors.error.main then use theme.colors.error.contrastText.

Text colors

Property When to use
theme.colors.text.primary The default text color
theme.colors.text.secondary Text color for things that should be a bit less prominent
theme.colors.text.disabled Text color for disabled / faint things
theme.colors.text.link Text link color
theme.colors.text.maxContrast Maximum contrast (absolute white in dark theme, absolute black in white theme)

Background colors

Property When to use
theme.colors.background.canvas Think dashboard background. A background surface for panels and panes that use primary background
theme.colors.background.primary The default content background for content panes and panels
theme.colors.background.secondary For cards and other surfaces that need to stand out when placed on top of the primary background

Borders

Property When to use
theme.colors.border.weak Primary border for panels and panes and other subtle borders
theme.colors.border.medium For stronger borders like inputs
theme.colors.border.strong For even stronger border like hover highlighted border

Actions

Property When to use
theme.colors.action.hover Background color for hover on card, menu or list item
theme.colors.action.focus Background color for focused card, menu or list item
theme.colors.action.selected Background color for selected card, menu or list item

Paddings and margins

Example Result
theme.spacing(1) 8px
theme.spacing(1, 2) 8px 16px
theme.spacing(1, 2, 0.5, 4) 8px 16px 4px 32px

Border radius

Example Result
theme.shape.borderRadius(1) 2px
theme.shape.borderRadius(2) 4px

Typography

For font family, font sizes and line heights use the variables under theme.typography.

Using ThemeContext directly

import { ThemeContext } from '@grafana/data';

<ThemeContext.Consumer>{(theme) => <Foo theme={theme} />}</ThemeContext.Consumer>;

Using withTheme higher-order component (HOC)

With this method your component will be automatically wrapped in ThemeContext.Consumer and provided with current theme via theme prop. Components used with withTheme must implement the Themeable interface.

import  { ThemeContext, Themeable } from '@grafana/ui';

interface FooProps extends Themeable2 {}

const Foo: React.FunctionComponent<FooProps> = () => ...

export default withTheme2(Foo);

Using theme in tests

If you need to pass a theme object to a function under test just import createTheme and call it without any arguments.

import { createTheme } from '@grafana/data';

describe('MyComponent', () => {
  it('should work', () => {
    result = functionThatNeedsTheme(createTheme());
    expect(result).toBe(true);
  });
});

FAQ

This section provides insight into frequently-asked questions.

How can I modify Sass variable files?

If possible, migrate styles to Emotion

For the following to apply you need to run yarn dev task.

[_variables|_variables.dark|_variables.light].generated.scss files are the ones that are referenced in the main Sass files for Sass variables to be available. These files are automatically generated and should never be modified by hand!

If you need to modify the sass variable files be sure to update the files that end with .tmpl.ts and not the .generated.scss files.