useTheme

Read the current theme as typed values

useTheme reads the current theme as a typed object whose values update with the surrounding theme context.

Tamagui themes operate much like CSS variables, so they can nest and override each other contextually.

The returned object proxies up through every parent theme to your tokens, just like CSS variables at runtime.

Example:

import { YStack, useTheme } from 'tamagui'
const App = () => {
const theme = useTheme()
return <YStack backgroundColor={theme['color-1'].val} />
}

The useTheme hook returns your Theme turned into a ThemeParsed, which means it turns all values into a Variable:

{
background: {
val: '#000',
variable: 'var(--background)',
name: 'background',
isVar: true,
},
color: {
val: '#fff',
variable: 'var(--color)',
name: 'color',
isVar: true,
},
}

The useTheme hook adds a .get() helper function on each Variable for performance. On web, .get() returns the .variable property and avoids re-rendering on value changes, because CSS custom properties handle updates directly in the browser. On native, .get() returns .val and re-renders on change. When the fastSchemeChange setting is enabled, get() returns a DynamicColorIOS value on iOS to avoid re-renders there as well. Passing get('web') restricts that optimization to web.

import { 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-render
const background = theme.background.get()
// if you needed to access it in a way that always returns the raw value
const backgroundValue = theme.background.val
return (
<SomeExternalComponent style={{ backgroundColor: background, }} />
)
}

You can mix and match useMedia and useTheme, and the compiler understands most basic usages, even with nested logic or constants within the file or imports whitelisted 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 { useTheme, html } from '@tamagui/core'
export default () => {
const theme = useTheme()
// access the value
console.log(theme.bg.val)
return <html.div backgroundColor={theme['color-1']} />
}

Reading another theme

useTheme takes no arguments and reads the ambient theme. To read values under a different theme, wrap the reader in <Theme name="..."> and call useTheme inside it.