useTheme
Creating and using theme values.
The hook for themes allows you to access theme values at runtime. If you use any of its values for style properties, the compiler will attempt to optimize them on the web. On native, theme values are left in the render function, if React Native supports themes at some point we could compile to that.
import { YStack, useTheme } from 'tamagui'const App = () => {const theme = useTheme()return <YStack backgroundColor={theme.color1} />}
The useTheme
hook returns a Variable
. When you run createTamagui
your returns themes are of type ThemeParsed
. This means that all the values have been converted from this:
{background: '#000',color: '#fff'}
into the type ThemeParsed
, which maps the values in the object to type Variable
:
{background: {val: '#000',variable: 'var(--background)',name: 'background',isVar: true,},color: {val: '#fff',variable: 'var(--color)',name: 'color',isVar: true,},}
The useTheme
hook uses proxies to track if you access variable
and avoid re-rendering.
If you access val
it will consider that theme value dynamic, and if the parent theme changes, it will re-render.
You can use .get()
on any value which will automatically resolve to variable
on the web, but val
on native.
import { Stack, useTheme } from '@tamagui/core'import { SomeExternalComponent } from 'some-external-component'const App = () => {const theme = useTheme()// on the web this is something like var(--background) and will avoid re-renders// on native it will be something like #fff and will re-renderconst background = theme.background.get()// if you needed to access it in a way that always returns the raw valueconst backgroundValue = theme.background.valreturn (<SomeExternalComponent style={{ backgroundColor: background, }} />)}
You can mix and match useMedia
and useTheme
, and the compiler undertands most basic usages, even with nested logic or constants within the file or imports white-listed in your build setup:
import { YStack, useMedia, useTheme } from 'tamagui'const App = () => {const theme = useTheme()const media = useMedia()return (<YStack y={media.sm ? 10 : 0} backgroundColor={media.lg ? theme.red : theme.blue} {...(media.xl && { y: theme.space2, })} />)}
This will compile on the web to:
const _cn =' _alignItems-1oszu61 _boxSizing-deolkf _display-6koalj _flexBasis-1mlwlqe _flexDirection-eqz5dr _flexShrink-1q142lx _transform-_sm_1exagq _transform-_sm0_1wpzndr _backgroundColor-_lg_no4z4g _backgroundColor-_lg0_1qoifqd _transform-_xl_gqa6p0'import { YStack, useMedia, useTheme } from 'tamagui'const App = () => {return <div className={_cn} />}
And the following CSS:
._alignItems-1oszu61 {-ms-flex-align: stretch;-webkit-align-items: stretch;-webkit-box-align: stretch;align-items: stretch;}._boxSizing-deolkf {box-sizing: border-box;}._display-6koalj {display: -webkit-box;display: -moz-box;display: -ms-flexbox;display: -webkit-flex;display: flex;}._flexBasis-1mlwlqe {-ms-flex-preferred-size: auto;-webkit-flex-basis: auto;flex-basis: auto;}._flexDirection-eqz5dr {-ms-flex-direction: column;-webkit-box-direction: normal;-webkit-box-orient: vertical;-webkit-flex-direction: column;flex-direction: column;}._flexShrink-1q142lx {-ms-flex-negative: 0;-webkit-flex-shrink: 0;flex-shrink: 0;}@media (max-width: 860px) {:root:root ._transform-_sm_1exagq {-webkit-transform: translateY(10px);transform: translateY(10px);}}@media not all and (max-width: 860px) {:root:root ._transform-_sm0_1wpzndr {-webkit-transform: translateY(0px);transform: translateY(0px);}}@media (min-width: 1120px) {:root:root:root ._backgroundColor-_lg_no4z4g {background-color: var(--red);}}@media not all and (min-width: 1120px) {:root:root:root ._backgroundColor-_lg0_1qoifqd {background-color: var(--blue);}}@media (min-width: 1280px) {:root:root:root:root ._transform-_xl_gqa6p0 {-webkit-transform: translateY(var(--space2));transform: translateY(var(--space2));}}
Using outside of styling
You can useTheme()
(and useMedia()
) at runtime. Like useMedia, useTheme will only re-render when it has to, and often you can skip re-renders altogether by either passing the values to a Tamagui styled component, or by using the helper getVariable
:
getVariable
If you access theme.bg.val
in your render function, the component will only re-render when theme.bg changes.
import { theme, Stack } from '@tamagui/core'export default () => {const theme = useTheme()// access the valueconsole.log(theme.bg.val)return (<Stack backgroundColor={theme.color1} />)}``` ## Changing the theme at the hook level This is a more advanced use for building custom hooks or components, but you can pass in a theme name and a component theme name (as [discussed here](/docs/intro/themes#component-subset-themes)) to grab the right subset theme: ```tsxfunction MyComponent(props) {const theme = useTheme(props.theme, 'MyComponent')}
For example, if you have the following themes:
dark
dark_green
dark_green_MyComponent
And this code:
<Theme name="dark"><MyComponent theme="green" /></Theme>
The above useTheme
hook would return the dark_green_MyComponent
theme.