UI Styling Standard
The eslint plugin to enforce and educate on Atlassian's UI Styling StandardThe UI Styling Standard is a set of principles to guide styling UI code across Atlassian's frontend codebases and ecosystem.
These are the current ESLint rules that enforce and help comply with the UI Styling Standard today, but more are planned to support the standard over time.
Examples
Check out the migration guide or individual rule documentation for examples.
Rules
| Rule | Description | Recommended | Fixable | Suggestions |
|---|---|---|---|---|
| atlaskit-theme | Ban certain usages of @atlaskit/theme that @compiled/react does not understand | |||
| convert-props-syntax | Convert props syntax that is unsupported by styled-components@<4 or @emotion/styled to props syntax that is supported. This is useful when used in conjunction with no-styled-tagged-template-expression, as output from the latter may use props syntax unsupported by those libraries. | Yes | Yes | |
| enforce-style-prop | Disallows usage of static styles in the style attribute in components | Yes | ||
| local-cx-xcss | Ensures the cx() function, which is part of the XCSS API, is only used within the xcss prop. This aids tracking what styles are applied to a jsx element. | Yes | ||
| no-array-arguments | Prevents usage of array arguments to style declaration functions | Yes | Yes | |
| no-atlaskit-theme | Disallow imports from @atlaskit/theme | Yes | ||
| no-classname-prop | Disallows usage of the className prop in JSX | Yes | ||
| no-container-queries | Prevents usage of @container query within css styling | Yes | ||
| no-dynamic-styles | Disallows use of dynamic styles in CSS-in-JS calls | Yes | ||
| no-exported-styles | Disallows exports of css, keyframes, styled and xcss | Yes | ||
| no-global-styles | Prevents global styles through CSS-in-JS or CSS module imports | Yes | ||
| no-important-styles | Disallows important style declarations | Yes | ||
| no-imported-style-values | Disallows imports of style values | Yes | ||
| no-nested-selectors | Prevents usage of nested selectors within css styling | Yes | ||
| no-styled | Disallows usage of the styled imports | Yes | ||
| no-unsafe-selectors | Disallows use of nested styles in css functions. | Yes | Yes | Yes |
| no-unsafe-values | Disallows styles that are difficult/impossible to statically anaylze. | Yes | ||
| no-unused-cssmap-properties | Detects unused properties in cssMap style objects that are not exported. Helps maintain clean code by identifying style variants that are defined but never used. | Yes | ||
| use-compiled | Ensures usage of @compiled/react or @atlaskit/css instead of other CSS-in-JS libraries | Yes | Yes | |
| @atlaskit/design-system/consistent-css-prop-usage | Ensures consistency with css and xcss prop usages | Yes | Yes | |
| @atlaskit/design-system/no-css-tagged-template-expression | Disallows any css tagged template expressions that originate from Emotion, Styled Components or Compiled | Yes | Yes | |
| @atlaskit/design-system/no-keyframes-tagged-template-expression | Disallows any keyframe tagged template expressions that originate from Emotion, Styled Components or Compiled | Yes | Yes | |
| @atlaskit/design-system/no-styled-tagged-template-expression | Disallows any styled tagged template expressions that originate from Emotion, Styled Components or Compiled | Yes | Yes | |
| @atlaskit/design-system/no-empty-styled-expression | Forbids any styled expression to be used when passing empty arguments to styled.div() (or other JSX elements). | Yes | ||
| @atlaskit/design-system/no-invalid-css-map | Checks the validity of a CSS map created through cssMap. This is intended to be used alongside TypeScript's type-checking. | Yes | ||
| @atlaskit/design-system/no-css-map-scoped | Disallows usage of the experimental cssMapScoped API from @compiled/react. This API is internal and is not part of the public Compiled CSS-in-JS interface. | Yes |
Purpose
For Atlassians, refer to the internal UI Styling Standard policy, (opens new window).
To enforce scoped encapsulation, type safety, and deterministic behavior in styling code that is present in other programming languages. This is a stepping stone to large performance improvements, reduced visual regressions, and enables testing and maintainability at scale. This approach improves readability and developer productivity via automation with tooling, testing, code migrations, and future advancements like generative AI.
Desired outcomes
- We can make large visual changes and migrations safely and in a fraction of the time.
- To have the vast majority of styling code be deterministic, immutable, and bound to its scope, reducing unknown visual and UX regressions.
- To enable teams to write tooling quicker that's better and more performant to lint, test, and migrate UI code to improve current and future developer productivity and satisfaction.
- To enable large performance improvements for customers and developers with a zero-runtime styling solution.
- To reduce the amount of overall custom styling code written while supporting customization without the need for hacks and technical debt.
- We aim to see a reduction of the “average styles per component”, reducing the effort to build and maintain UIs.
Core principles
We want the styling ecosystem (CSS, CSS-in-JS, and parts of JSX) at Atlassian and the wider ecosystem we support to be as mature as the other code we write, such as TypeScript/JavaScript, Java, Go, etc.
Like other languages, styling code must be:
- type-safe
- static and locally analyzable
- reusable and composable
- restricted to an encapsulated scope
- deterministic—with styling known in isolation
- discoverable and readable without deep knowledge of the CSS spec
As the W3C CSS spec and wider industry grows, having our styling code meet these principles will mean we can programmatically evolve that a better future state.
Style constraints
Following our core principles, we've developed a set of style constraints.
All styles must be:
- applied with the
cssorxcssprop - declared as objects with the
css()orxcss()function - declared at the top-most scope of the module
- declared in the same module that they are used in
- static, not dynamic
Additionally, styles cannot be:
- global (outside of a repo-wide reset like the CSS Reset)
- exported or imported between modules
- combined using the spread operator
- declared with nested selectors
These constraints unlock major performance improvements for Compiled, (opens new window) and raise the floor for static analysis — enabling code evolution at scale.
Benefits
The above style constraints provide numerous benefits:
Linters can exhaustively lint all declared styles (all styles have an associated element without indirection).
All element styles can be statically known, unlocking code transformation at scale through codemods.
Styles are typed end-to-end and can be narrowed, enabling safe, explicit and bounded style overrides.
Improved runtime performance, especially by eliminating dynamic styles.
Allows for effective build-time optimization when using compile time CSS-in-JS libraries such as Compiled, (opens new window).
The impacts of style changes can be better understood by developers, preventing regressions and incidents.