The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/contribute/style-guides/styling.md

118 lines
3.0 KiB

# Styling Grafana
[Emotion](https://emotion.sh/docs/introduction) is our default-to-be approach to styling React components. It provides a way for styles to be a consequence of properties and state of a component.
## Usage
### Basic styling
For styling components, use [Emotion's `css` function](https://emotion.sh/docs/emotion#css).
```tsx
import React from 'react';
import { css } from '@emotion/css';
const ComponentA = () => (
<div
className={css`
background: red;
`}
>
As red as you can get
</div>
);
```
### Styling with theme
To access the theme in your styles, use the `useStyles` hook. It provides basic memoization and access to the theme object.
> Please remember to put `getStyles` function at the end of the file!
```tsx
import React, { FC } from 'react';
import { GrafanaTheme } from '@grafana/data';
import { useStyles } from '@grafana/ui';
import { css } from '@emotion/css';
const Foo: FC<FooProps> = () => {
const styles = useStyles(getStyles);
// Use styles with classNames
return <div className={styles}>...</div>;
};
const getStyles = (theme: GrafanaTheme) => css`
padding: ${theme.spacing.md};
`;
```
### Styling complex components
In more complex cases, especially when you need to style multiple DOM elements in one component, or when using styles that depend on properties and/or state, you should create a helper function that returns an object of styles. This function should also be wrapped in the `stylesFactory` helper function, which will provide basic memoization.
Let's say you need to style a component that has a different background depending on the `isActive` property :
```tsx
import React from 'react';
import { css } from '@emotion/css';
import { GrafanaTheme } from '@grafana/data';
import { selectThemeVariant, stylesFactory, useTheme } from '@grafana/ui';
interface ComponentAProps {
isActive: boolean;
}
const ComponentA: React.FC<ComponentAProps> = ({ isActive }) => {
const theme = useTheme();
const styles = getStyles(theme, isActive);
return (
<div className={styles.wrapper}>
As red as you can get
<i className={styles.icon} />
</div>
);
};
// Mind, that you can pass multiple arguments, theme included
const getStyles = stylesFactory((theme: GrafanaTheme, isActive: boolean) => {
const backgroundColor = isActive ? theme.colors.red : theme.colors.blue;
return {
wrapper: css`
background: ${backgroundColor};
`,
icon: css`
font-size: ${theme.typography.size.sm};
`,
};
});
```
For more information about themes at Grafana please see the [themes guide](./themes.md).
### Composing class names
For class composition, use [Emotion's `cx` function](https://emotion.sh/docs/emotion#cx).
```tsx
import React from 'react';
import { css, cx } from '@emotion/css';
interface Props {
className?: string;
}
const ComponentA: React.FC<Props> = ({ className }) => {
const finalClassName = cx(
className,
css`
background: red;
`
);
return <div className={finalClassName}>As red as you can ge</div>;
};
```