UI Styling Standard

The eslint plugin to enforce and educate on Atlassian's UI Styling Standard

no-dynamic-styles

Blocks dynamic styles (function expressions) in style declarations.

This ensures that style declarations:

  • are statically analyzable
  • can be efficiently extracted into atomic CSS
  • are more readable and deterministic, thus easier to maintain

Examples

Incorrect

import { styled } from '@compiled/react';

const Component = styled.div<{ width: number }>((props) => ({
    width: props.width,
}));
import styled from 'styled-components';

const Component = styled.div<{ width: number }>({
    width: (props) => props.width,
});
import styled from 'styled-components';

const Container = styled.div<{ hasPadding: boolean }>({
    padding: ({ hasPadding }) => (hasPadding ? token('space.100', '8px') : token('space.0', '0px')),
});

The following example shows the code leading to a bug. In this scenario Compiled transforms the whole function into the result of its first return statement (static string '0 0 0 1px magenta'):

import { styled } from '@compiled/react';

const Component = styled.li({
    boxShadow: (props) => {
        if (props.isSelected) {
            return '0 0 0 1px magenta';
        }

        return '0 0 0 1px green';
    },
});

See more about this issue here.

Correct

Define all styles statically, and dynamically apply them using the css prop. Use the style prop for values that are only known at runtime.

For further guidance, consult our migration guide.

Flags

If you have a style that is on/off depending on a prop, use the css prop to conditionally apply it.

import { css } from '@compiled/react';

const baseStyles = css({ padding: token('space.0') });
const hasPaddingStyles = css({ padding: token('space.100') });

const Container = ({ hasPadding = false }: { hasPadding?: boolean }) => {
    return <div css={[baseStyles, hasPadding && hasPaddingStyles]} />;
};

Variants

If you have variants which are known ahead of time, use cssMap to define them and the css prop to conditionally apply it.

import { css } from '@compiled/react';

const baseStyles = css({ width: 100 });
const stylesMap = cssMap({
  primary: {
    background: token('color.background.brand.bold'),
    '&:hover': { background: token('color.background.brand.bold.hovered') },
  },
  error: {
    background: token('color.background.warning.bold'),
    '&:hover': { background: token('color.background.warning.bold.hovered') },
  }
});

const Wrapper = ({ appearance = 'primary' }: { appearance?: 'primary' | 'error' }) => (
  <div css={[baseStyles, stylesMap[appearance]} />
);

Dynamic values

If you have styles which are truly dynamic, use the style prop.

This approach should be used as a last resort.

import { css } from '@compiled/react';

const Component = ({ width }: { width: number }) => {
    return <div style={{ width }} />;
};
import { css } from '@compiled/react';

const containerStyles = css({
    '&::before': {
        width: 'var(--ak-example-width)',
    },
});

function Example({ width }: { width: number }) {
    return <div css={containerStyles} style={{ '--ak-example-width': `${width}px` }} />;
}

Options

importSources: string[]

By default, this rule will check styles using:

  • @atlaskit/css
  • @atlaskit/primitives
  • @compiled/react
  • @emotion/react
  • @emotion/core
  • @emotion/styled
  • styled-components

Override this list with the importSources option, which accepts an array of package names.

Was this page helpful?
We use this feedback to improve our documentation.