Variants
Simple typed prop styles through styled()
Variants turn a small set of typed component props into reusable groups of styles.
Variants expand a single prop into a group of styles. Example:
Notice the as const on the variant definition object. This is necessary to please
TypeScript until it gains the ability to infer constant objects. If left out, your types
may break.
Usage:
This component uses a few different types of variants, expanded on below.
Why variants?
Sharing plain style objects means typing props by hand and gluing them together with arbitrary logic inside a functional component. The types may not map to the actual output, and a compiler cannot optimize what it cannot see.
Variants force you out of the React render function, which means no hooks and a
much clearer contract: a dynamic takes one value and the style environment, and
outputs a statically-shaped group of styles. Sibling-prop logic belongs in a
component .resolve callback.
Because variants work with the styled function, they nest without adding depth
to your render tree. styled(styled()) is a single React component that the
compiler can optimize and flatten.
Variants
Typed variants
true or false
The special keys true and false will map to a boolean. So the centered
prop will be typed to accept true or false, and when true it will apply its
styles.
String, boolean, and number domains
For an open-ended value domain, declare the prop type on styled.dynamic.
There is no runtime type-key lookup:
Use an exact-key object when the domain is finite, or one dynamic when it is
parametric. A key such as string, number, or Size is otherwise just an
exact literal key.
Dynamic token variants
When you write variants, you have to be explicit so TypeScript and the runtime
know exactly which props you accept. This can be especially cumbersome when you
want to “gather” all the values of a specific token scale. For example, without
a dynamic, if you wanted to have a pad property that accepted all the
keys from tokens.size, you’d have to write this:
This is verbose, and every token change means updating every component. With a dynamic instead:
Dynamic variants save you from hardcoding every token key. The generic parameter is the accepted prop type, so one callback can cover a token scale, raw values, or a union without runtime type-key matching:
Environment passed to dynamic variants
The second argument contains the current tokens, theme, and fonts. It never
contains component props. Use .resolve((props, env) => ...) when styles depend
on sibling props.
Usage:
The second argument is always
{ theme, tokens, fonts, font, fontFamily }.
Props
theme
ThemeParsed
A proxy to your theme that lets you access active theme values using normal keys.
tokens
TokensParsed
All tokens parsed from your configuration, accessible with bare keys (e.g. tokens.size[val]).
font
Font
Maybe undefined. A single resolved Font object from your font configuration.
fontFamily
string
Maybe undefined. The name of the current fontFamily.
fonts
GenericFonts
All fonts parsed from your configuration.
Bare dynamic declarations
When variant styles depend on sibling props, declare the prop type with bare styled.dynamic<T>() and apply the styles in a component .resolve callback:
Bare dynamic variants declare the accepted prop type and mark the prop as consumed. It is not forwarded to the underlying DOM element or native view.
Dynamic value domains
Use the dynamic’s generic parameter to declare the whole accepted domain, then branch on the value inside the callback when needed:
Dynamic variants
If you need more complex types, use styled.dynamic to brand the value-to-style
function and declare the prop type:
The callback is invoked once per active flat-clause payload, so responsive and stateful values keep the same behavior as exact variants.
defaultVariants
Sometimes you’d like to set a default value for a variant you’ve just set on your styled() component. Due to the way Typescript types parse from left to right, we can’t properly type variants directly on the object you define them on.
The defaultVariants option allows you to set these, properly typed:
Variants and flat clauses
Variant branches can use the same state and media clauses as any other style value, in string or object form:
The variant prop itself accepts conditions too, so a variant can change per state or breakpoint:
Variants and parent variants
Styled components can access their parent components variants, even in their variants: