Basic rules to follow when authoring React UI CSS.
React UI uses Stylelint to avoid errors in CSS and enforce unified coding style across all stylesheets.
stylelint-config-visionapps-order— an opinionated list of CSS properties order.
stylelint-config-css-modules— tweak of Stylelint rules for CSS modules.
Without Web Components, there is no such thing as a complete encapsulation of a component. Inside browser window, a React app is still a bunch of HTML and CSS (and JS, of course) living in the same global context. Developers can fight against CSS cascade, inheritance and specificity, or accept these principles, and even benefit from them. Understanding how CSS works and making use of this knowledge leads towards smaller stylesheets, easier maintenance, and better performance.
To be able to handle CSS at such a large scale of a UI library, React UI works in harmony with fundamental CSS principles. Most importantly, all CSS is written in specificity order, i.e. from lowest to highest specificity. This idea was most famously shaped and popularized by Harry Roberts in his ITCSS architecture. React UI draws inspiration from ITCSS which can be seen the best in the foundation CSS layer (and its source).
There are three simple rules to follow when organizing React UI CSS:
- Component styles must be placed in component's directory.
- Components must not import other component's styles.
- Any CSS that needs to be shared across multiple components and/or global
styles must be placed in the
👉 All React UI CSS is written in Sass. Learn more about preprocessing with Sass.
└── lib Main source directory, contains global Sass endpoints
├── components React components with their stylesheets
├── _settings.scss Component's non-themeable Sass variables
├── _theme.scss Component's Sass interface to its CSS custom properties in `theme.scss`
├── _tools.scss Component's Sass mixins and functions
├── Component.scss Component's main stylesheet
├── styles Partials for top-level Sass endpoints and shared styles
├── elements Styles for unclassed HTML elements (type selectors)
├── generic Global ground-zero styles
├── helpers Helper classes
├── settings Sass variables shared across global styles and/or multiple components
├── theme Sass interface to `theme.scss`, used in global styles or across multiple components
├── theme-constants Sass variables for use only within `theme.scss`
├── tools Sass mixins and functions shared across global styles and/or multiple components
└── _utilities.scss Sass loop that generates utility classes from `settings/_utilities.scss` config
├── foundation.scss Mandatory themeable CSS layer, ground-zero for React components
├── helpers.scss Optional set of helper and utility classes
└── theme.scss Default theme, a collection of hundreds of CSS custom properties
React UI leverages CSS modules (not to be confused with modular CSS specification of the same name) to take advantage of writing native CSS (meaning “not JSS or CSS in JS”). Together with Sass, CSS modules represent flexibility and popular programming features needed to author modern stylesheets perfectly familiar to traditional CSS developers.
CSS modules help keeping source class names short and clear. The same class name can be used in another component with different styling. Final class names are converted by tooling and composed of component name, original class name, and a random suffix which makes them unique in global context of the whole web app.
For example, this JSX:
… with this SCSS:
… produces following CSS class names:
Resulting CSS class names are both unique and human-readable at the same time which is convenient for development. Class names are further shortened and obfuscated for production environments.
Helpers and Utilities
There are also global helper and utility classes (both documented as CSS Helpers
for the sake of comprehensibility for non-CSS guys) that can be used by
developers and thus remain unaltered by CSS modules. For example,
:global(.display-block) selector produces
display-block CSS class.
Class Naming Rules
Following rules make it clear both in JSX and CSS what is affected by a CSS class.
Short, preferably single-word names should be chosen for all component elements. No naming convention like BEM or SUIT CSS needs to be applied since class names are unique in the global scope thanks to CSS modules. Conventions for modifier classes are covered by the rules below.
Component's top-level HTML element must have
rootclass name. However, this rule has a few exceptions:
When the component is a subcomponent, it's usually better to use subcomponent's name, e.g.
group. This enables us to keep related CSS of both the main component and its subcomponents in a single file and see the big picture during development.
When no CSS on the root element is necessary and styling only takes place once a visual modification is invoked by component props,
rootclass name can be omitted entirely.
Modifier class names related to the current HTML element must start with
isand contain the name of the target element, e.g.
label). However, child elements may be modified as well, e.g. by a CSS selector like
.isRootRequired > .label(root is marked as required but the label is what needs to be visually modified).
Modifier class names related to child elements must start with
hasand refer to the element in question, e.g.
hasRootSmallInput(applies styling on
rootbut relates to
There are three kinds of custom properties used:
--rui-local-*for internal (component-scoped, local) custom properties. May reuse other custom property types.
--rui-custom-*for any custom properties whose value comes from component's API. May reuse other custom property types.
--rui-*(unscoped for the sake of brevity) for theme-related custom properties. Part of public API, designed to be customized. Must not reuse other custom property types. Refer to the theming overview to learn how their names are created.
Preprocessing with Sass
All React UI CSS source is written in SCSS syntax of Sass preprocessor.
Sass variables, mixins and functions must use kebab-case notation.
Only Sass modules must be used to organize Sass source files,
@importis deprecated. Using scoped variables, mixins and functions (those starting with
_) is highly recommended whenever appropriate.
Built-in Sass modules should be preferred over older Sass functions that are deprecated, e.g.
Mixins that lead to duplicate CSS should be avoided. If possible, combine multiple CSS selectors for the desired rule set to achieve the same result.
Extend functionality should be avoided entirely due to its hardly predictable behavior.
Classes that are automatically generated by Sass loops should be handled with care. With loops, it's easy to produce a lot of CSS and negatively impact performance.