Components and their tree are styled through style sheets created with the
method. For the purpose of this documentation, let's say we're building a button component that
renders many elements and components, we would have a style sheet that looks something like the
In the example above, the keys of the object are known as selectors, with each selector being a combination of element and optional modifier (separated by an underscore). This is similar to the popular BEM syntax, without the "block", as our style sheet is the block (since styles are isolated). Style sheets support as many selectors as needed!
There are 2 types of selectors, the first being basic selectors, which includes pseudo elements, pseudo classes, and HTML attributes that are deterministic and do not have permutations. They can be defined as nested style objects directly on the element's style object.
The other type is advanced selectors, which includes combinators, as well as pseudos and attributes that do have permutations. Furthermore, multiple selectors can be defined at once using a comma separated list.
Advanced selectors must be nested within a
@selectors object as they can not be properly typed
Media and feature queries can be defined within a style object using
respectively. Both types require an object that maps query expressions to nested style objects.
@supportsmay be nested within itself and each other.
You can utilize the design system token's for consistent media query breakpoints.
Fonts are special as they need to be defined on the document instead of an element, which should be
done with a theme style sheet. However, we provide some convenience through the
fontFamily property, which can accept one or many font face objects.
Unlike normal CSS font faces, a font face object requires a
srcPath property, with a list of
file paths, instead of a
Animations have the same semantics as fonts and should be defined on a document using a
theme style sheet, but also like fonts, we provide some convenience through the
animationName property, which accepts a single keyframes object.
A rarely used but necessary feature for progressive enhancement and supporting legacy browsers.
Fallbacks allow you to define one or many different values for a single property through the
Variants are a staple feature of many components -- especially commonly used ones like buttons, alerts, and labels -- and encompasses everything from sizing (small, large) to palettes (positive, negative, etc).
With that being said, the guiding principle behind variants is that only 1 may ever be active at a time. If you need to apply more than 1, then you should use the element-modifier syntax mentioned at the beginning of the chapter.
To utilize variants, we define a
@variants object on a per element basis that maps each variant
type:enum) using nested objects. Variant names are critically important as they must match what's
Variant names must be formatted correctly! Each name combines a type to an enumerated value with a
:. Both the type and enum support alphanumeric characters, while the enum also supports
-. The type must start with a letter.
How a variant gets applied is highly dependent on the integration you are using, but it basically boils down to the following class name generation. Pass an object of variants and their enumerations as the 1st argument!
When handling default styles for a variant, you must define it as a variant instead of defining it on the element directly. This is necessary as it avoids style collisions and specificity issues.
When you need to set variant styles based on a combination of other variants, you can combine them
+ operator. This synax should be familiar as it's based on CSS.
Using the example above, say we want to bold the text when the
size is large, and the
brand, we would do the following:
You can combine as many variants as you'd like! Just be sure the variant names are properly combined with
While we support variants per element, we also support overrides on the style sheet. When defined at this level, any override deemed active will be deeply merged into a single style sheet in the order of: base < color scheme < contrast level < theme.
This feature will override any selector, element, element at-rule (even their variants), or nested style object from the base style sheet! This makes it very powerful and very robust.
addColorSchemeOverride() method for overrides depending on the "light" or "dark" color
scheme of the currently active theme. This is perfect for making slight changes to a theme between
the two modes.
This is equivalent to the native
prefers-color-scheme media query.
addContrastOverride() method for overrides depending on the "low" or "high" contrast level
of the currently active theme. This is perfect for providing accessible themes.
This is equivalent to the native
prefers-contrast media query.
And finally, use the
addThemeOverride() method for overrides depending on the currently active
theme itself. This provides granular styles on a theme-by-theme basis, perfect for style sheets that
are provided by third-parties.
Theme names must match the names passed to
Rendering a style sheet into CSS and injecting into the document is typically handled by an
integration and abstracted away from the consumer (see
useStyles() in the React package). However,
if you would like to render styles manually, you may do so with the
This method requires the style sheet instance as the 1st argument, and returns an object of class names mapped to their selector.