Skip to content

Variants

Variants helps you to create a more flexible and reusable stylesheet eg. for your base components. You can mix them with other Unistyles features like media queries and breakpoints.

Variants are objects that can be nested in any style object:

const styles = StyleSheet.create(theme => ({
container: {
backgroundColor: theme.colors.background,
variants: {
// here you can define your variants
}
},
text: {
color: theme.colors.text,
variants: {
// here you can define other variants!
}
}
}))

Variants contain groups of atomic variants.

To define a group, first you need to name it and then define variants within it:

const styles = StyleSheet.create(theme => ({
container: {
flex: 1,
variants: {
color: {},
size: {},
otherGroupName: {}
}
}
}))

These groups will later be used to select your variants, so remember to name them appropriately.

With the given structure, you can now define your variants that can contain any number of styles. You can also use breakpoints, media queries or styles like transform:

const styles = StyleSheet.create(theme => ({
container: {
flex: 1,
variants: {
color: {
primary: {
backgroundColor: theme.colors.primary
},
secondary: {
backgroundColor: theme.colors.secondary
}
},
size: {
small: {
width: 100,
height: 100
},
medium: {
width: 200,
height: 200
},
large: {
width: 300,
height: 300
}
},
otherGroupName: {
// other variants
}
}
}
}))

With your named groups, you can now select any variant from your stylesheet using the useVariants:

import { StyleSheet } from 'react-native-unistyles'
const Component = () => {
styles.useVariants({
color: 'primary',
size: 'small'
})
return (
<View style={styles.container} />
)
}
const styles = ...

TypeScript will provide perfect autocompletion for your variants, ensuring accuracy!

You can also use boolean values to select variants:

import { StyleSheet } from 'react-native-unistyles'
const Component = ({ isPrimary, isDisabled }) => {
styles.useVariants({
color: !isDisabled,
borderColor: isPrimary
// you can also use strings
// color: "true" | "false"
})
return (
<View style={styles.container} />
)
}
const styles = StyleSheet.create(theme => ({
container: {
// other styles
variants: {
color: {
true: {
backgroundColor: theme.colors.primary
},
false: {
backgroundColor: theme.colors.disabled
},
// you can still specify a default variant
default: {
backgroundColor: theme.colors.barbie
},
// or other variants
special: {
backgroundColor: theme.colors.special
}
},
borderColor: {
true: {
borderColor: theme.colors.primary
}
// you can also skip "false" here
}
}
}
}))

If you specify a boolean variants like “true”, there is no requirement to specify a “false” variant (and vice versa). You can mix boolean variants with other variants as well.

Variant names can also be numbers:

const Component = ({ level }: { level: 1 | 2 }) => {
styles.useVariants({
level
})
return (
<Text style={styles.heading}>
Heading
</Text>
)
}
const styles = StyleSheet.create(theme => ({
heading: {
variants: {
level: {
1: {
fontSize: 32
},
2: {
fontSize: 24
}
}
}
}
}))

On iOS and Android, numeric values are converted to integers, so use whole numbers as variant names.

You can define a default variant that will be used when you don’t pass any variant to the useVariants hook:

const styles = StyleSheet.create(theme => ({
container: {
flex: 1,
variants: {
color: {
primary: {
backgroundColor: theme.colors.primary
},
secondary: {
backgroundColor: theme.colors.secondary
},
default: {
backgroundColor: theme.colors.barbie
}
}
}
}
}))

If you pass an empty object, Unistyles will try to find the default variant in your stylesheet:

styles.useVariants({}) // will use default variant (if any)

useVariants always expects an object, so don’t call it with undefined.

styles.useVariants({
color: undefined // will use default variant (if any)
})

At runtime, a null value is treated the same way as undefined.

Lastly, you can pass the correct variant name for a variant group:

styles.useVariants({
color: 'secondary' // will use secondary variant
})

Variants were designed to be used as component props:

import React from 'react'
import { StyleSheet } from 'react-native-unistyles'
type ComponentProps = {
color: 'primary' | 'secondary'
size: 'small' | 'medium' | 'large'
}
const Component: React.FunctionComponent<ComponentProps> = ({ color, size }) => {
styles.useVariants({
color,
size
})
return (
<View style={styles.container} />
)
}

Instead of using enum or strings with | , you can use UnistylesVariants to infer the type of your variants:

import React from 'react'
import { StyleSheet, UnistylesVariants } from 'react-native-unistyles'
type ComponentProps = UnistylesVariants<typeof styles>
const Component: React.FunctionComponent<ComponentProps> = ({ color, size }) => {
styles.useVariants({
color,
size
})
return (
<View style={styles.container} />
)
}
// infers type of your variants from the stylesheet below
const styles = ...

Defining the same variant across multiple styles

Section titled “Defining the same variant across multiple styles”

It’s possible to define the same variant group across multiple styles:

const styles = StyleSheet.create(theme => ({
container: {
flex: 1,
variants: {
size: {
small: {
width: 100,
height: 100
},
medium: {
width: 200,
height: 200
},
large: {
width: 300,
height: 300
}
}
}
},
text: {
fontWeight: 'bold',
variants: {
size: {
small: {
fontSize: 12
},
medium: {
fontSize: 16
},
large: {
fontSize: 20
}
}
}
}
}))
const styles = StyleSheet.create(theme => ({
container: {
flex: 1,
variants: {
size: {
small: {
width: 100,
height: 100
},
medium: {
width: 200,
height: 200
},
large: {
width: 300,
height: 300
}
}
}
},
text: {
fontWeight: 'bold',
variants: {
size: {
// only small variant!
small: {
fontSize: 12
}
}
}
}
}))

In this case, the generated TypeScript type will be:

size?: 'small' | 'medium' | 'large'

TypeScript also infers the style properties defined inside your variants. This works for styles that mix regular properties with variants, as well as for styles that contain only variants:

const styles = StyleSheet.create({
container: {
flex: 1,
variants: {
size: {
small: { width: 100 },
large: { width: 300 }
}
}
},
badge: {
variants: {
color: {
red: { backgroundColor: 'red' },
blue: { backgroundColor: 'blue' }
}
}
}
})
styles.container.width // number
styles.badge.backgroundColor // string