styled()

Extend and build custom and optimizable components.

For custom styled() components to be optimized by the compiler, you'll need to place them in a node module and update your build configuration. See the Design Systems guide.
Create a new component by extending an existing one:
import { styled, Stack } from 'tamagui'
export const Circle = styled(Stack, {
borderRadius: 100_000_000,
})
Usage:
<Circle x={10} y={10} backgroundColor="red" />
The styled function only accepts Tamagui components or components that accept the className property, for now. Because react-native-web components explicitly don't accept className, components like TextArea are currently not working with Tamagui. We're working to expand this support in an upcoming release. You can pass any prop that is supported by the component you are extending, even variants of the parent component. Tamagui will figure out the style props up-front, turn them into classNames, and then pass the non-style props down to the component as defaultProps. Variants
Let's add some variants:
import { styled, Stack } from 'tamagui'
export const Circle = styled(Stack, {
borderRadius: 100_000_000,
variants: {
pin: {
top: {
position: 'absolute',
top: 0,
},
},
centered: {
true: {
alignItems: 'center',
justifyContent: 'center',
},
},
size: {
'...size': (size, { tokens }) => {
return {
width: tokens.size[size] ?? size,
height: tokens.size[size] ?? size,
}
},
},
},
})
We can use these like so:
<Circle pin="top" centered size="$lg" />
Notice here we're showing off a few different styles of variants. We'll expand on them below: Boolean Variants
The special key true will map to a boolean property. So the centered prop will be typed to accept true or false, and when true it will apply it's styles. Spread 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. For example, without spread variants, if you wanted to have a pad property that accepted all the keys from tokens.size, you'd have to write this:
// in your tamagui.config.ts:
const tokens = createTokens({
size: {
sm: 10,
md: 15,
lg: 25,
// ...
}
})
export default createTamagui({
tokens
})
// somewhere in your app:
const MyButton = styled(Stack, {
variants: {
pad: {
sm: {
padding: tokens.size.sm,
},
md: {
padding: tokens.size.md,
},
lg: {
padding: tokens.size.lg,
},
// ...
}
}
})
// now you can
<MyButton pad="$lg" />
This is verbose, and only gets more verbose if you add more sizes. It would require always updating every component every time you change the tokens. Spread variants solve this problem. Instead, we can write:
// in your tamagui.config.ts:
const tokens = createTokens({
size: {
sm: 10,
md: 15,
lg: 25,
// ...
}
})
export default createTamagui({
tokens
})
// somewhere in your app:
const MyButton = styled(Stack, {
variants: {
pad: {
'...size': (val, { tokens }) => ({
padding: tokens.size[val]
}),
}
}
})
// now you can
<MyButton pad="$lg" />
Spread variants save you from having to define hardcoded styles for every key (sm, md, lg) in your token object. They collect values from any of your top level token categories. So you can only use ...color, ...size, ...space, ...font, ...fontSize, ...lineHeight, ...radius, ...letterSpace, or ...zIndex. They must be prefixed with ... as that is how they are typed properly and assembled for runtime. The Spread variant function will receive two arguments: the first is the value given to the property ("$lg"), and the second is an object with { theme, tokens, props }.
  • theme of type ThemeParsed, the current active theme but the keys all start with $.
  • tokens of type TokensParsed, the tokens from createTokens, but the keys all start with $.
Because you can expand them to any number of styles, they can save a ton of code:
const MyButton = styled(Stack, {
variants: {
square: {
'...size': (size, { tokens }) => {
// size === '$lg'
// tokens.size.$lg === 25
return {
width: tokens.size[size] ?? size,
height: tokens.size[size] ?? size,
}
},
},
}
})