Skip to main content

Variants

The "variants" pattern allows you to conditionally apply one of several predefined styles based on a value. This is especially useful for theming or dynamic component behavior.

It is common to have different styles for different "variants" of a component. Some other styling solutions provide an explicit API for defining variants. In StyleX, you can define variants with a simple pattern instead.

Example: Button Variants

Here’s how you can create a button component with different visual styles based on variant props:

import * as stylex from '@stylexjs/stylex';

const styles = stylex.create({
base: {
appearance: 'none',
borderWidth: 0,
},
});
const colorVariants = stylex.create({
primary: {
backgroundColor: {
default: 'blue',
':hover': 'darkblue',
},
color: 'white',
},
secondary: {
backgroundColor: {
default: 'gray',
':hover': 'darkgray',
},
color: 'white',
},
});
const sizeVariants = stylex.create({
small: {
fontSize: '1rem',
paddingBlock: 4,
paddingInline: 8
},
medium: {
fontSize: '1.2rem',
paddingBlock: 8,
paddingInline: 16
},
});

type Props = {
color: keyof typeof colorVariants,
size: keyof typeof sizeVariants,
...
};

function Button({
color = 'primary',
size = 'small',
...props
}: Props) {
return (
<button
{...props}
{...stylex.props(
styles.base,
colorVariants[color],
sizeVariants[size],
props.style
)}
/
>);
}

// Usage
<Button color="primary" size="medium">Primary</Button>
<Button color="secondary">Secondary</Button>

Compound Variants

Sometimes variants are dependent on a combination of variants props.

In most cases, it's simpler to leverage StyleX’s deterministic style merging to simplify this behaviour.

Example: A disabled prop

import * as stylex from '@stylexjs/stylex';

const styles = stylex.create({
base: {...},
disabled: {
backgroundColor: 'grey',
color: 'rgb(204, 204, 204)',
cursor: 'not-allowed',
},
});
const colorVariants = stylex.create({
primary: {
backgroundColor: {
default: 'blue',
':hover': 'darkblue',
},
color: 'white',
},
secondary: {
backgroundColor: {
default: 'gray',
':hover': 'darkgray',
},
color: 'white',
},
});
const sizeVariants = stylex.create({...});

type Props = {
color?: keyof typeof colorVariants,
size?: keyof typeof sizeVariants,
disabled?: boolean,
...
};

function Button({
color = 'primary',
size = 'small',
disabled = false,
...props,
}: Props) {
return (
<button
{...props}
{...stylex.props(
styles.base,
colorVariants[color],
sizeVariants[size],
disabled && styles.disabled,
disabled && {
backgroundColor: 'grey',
color: 'rgb(204, 204, 204)',
cursor: 'not-allowed',
props.style
)}
/>
);
}

// Usage
<Button color="primary" size="medium">Primary</Button>
<Button color="secondary">Secondary</Button>

There may be other scenarios where you need to be more explicit about the styles that should applied under various condition. You can do this by declaring multiple style definitions for a particular variant.

Example: Two definitions for color variant styles

import * as stylex from '@stylexjs/stylex';

const styles = stylex.create({
base: {...},
});
const colorVariantsEnabled = stylex.create({
primary: {
backgroundColor: {
default: 'blue',
':hover': 'darkblue',
},
color: 'white',
},
secondary: {
backgroundColor: {
default: 'gray',
':hover': 'darkgray',
},
color: 'white',
},
});
const colorVariantsDisabled = stylex.create({
primary: {
backgroundColor: 'blue',
color: 'white',
},
secondary: {
backgroundColor: 'gray',
color: 'white',
},
});
const sizeVariants = stylex.create({...});

type Props = {
color?: keyof typeof colorVariants,
size?: keyof typeof sizeVariants,
disabled?: boolean,
...
};

function Button({
color = 'primary',
size = 'small',
disabled = false,
...props,
}: Props) {
const colorVariants = disabled
? colorVariantsDisabled
: colorVariantsEnabled;

return (
<button
{...props}
{...stylex.props(
styles.base,
colorVariants[color],
sizeVariants[size],
props.style
)}
/>
);
}

// Usage
<Button color="primary" size="medium">Primary</Button>
<Button color="secondary">Secondary</Button>