library/tamagui.mdx
Tamagui is a style library @tamagui/core, and a separate UI kit tamagui. It
also has an optional optimizing compiler @tamagui/static that generally you
only use through it's bundler plugins like @tamagui/vite-plugin or
@tamagui/babel-plugin for Metro.
Note tamagui is a superset of @tamagui/core, so you can use that in general
for code generation.
For the core style library you can do inline styles:
import { View, Text } from 'tamagui'
export default () => (
<>
<View backgroundColor="red" />
<Text fontSize={16} color="$colorToken" />
</>
)
Or you can use styled():
import { styled, View } from 'tamagui'
const CustomView = styled(View, {
margin: 10,
variants: {
spaced: {
true: {
margin: 20,
},
},
} as const,
})
For more on styled, there's a doc styled.mdx you can look up. Variants
generally can do a lot:
import { View, styled } from '@tamagui/core'
export const RoundedSquare = styled(View, {
borderRadius: 20,
variants: {
pin: {
// string values
top: {
position: 'absolute',
top: 0,
},
},
centered: {
// boolean
true: {
alignItems: 'center',
justifyContent: 'center',
},
false: {
alignItems: 'flex-start',
},
},
size: {
// functional that take all "size" tokens, so <View size="$sm" /> passes into here
'...size': (size, { tokens }) => {
return {
width: tokens.size[size] ?? size,
height: tokens.size[size] ?? size,
}
},
},
} as const,
})
You can define your configuration for Tamagui using createTamagui, and it lets
you define things, there's a readme in the docs called configuration.mdx you
can look up for more on this:
import { createTamagui, getConfig } from '@tamagui/core'
export const config = createTamagui({
// act like CSS variables at your root
tokens: {
// width="$sm"
size: { sm: 8, md: 12, lg: 20 },
// margin="$-sm"
space: { '-sm': 8 },
// radius="$none"
radius: { none: 0, sm: 3 },
color: { white: '#fff', black: '#000' },
},
themes: {
light: {
bg: '#f2f2f2',
color: '#fff',
},
dark: {
bg: '#111',
color: '#000',
},
},
// media query definitions can be used to style,
// but also can be used with "groups" to do container queries by size:
media: {
sm: { maxWidth: 860 },
gtSm: { minWidth: 860 + 1 },
short: { maxHeight: 820 },
hoverNone: { hover: 'none' },
touch: { pointer: 'coarse' },
},
shorthands: {
// <View px={20} />
px: 'paddingHorizontal',
},
settings: {
disableSSR: true, // for client-side apps gains a bit of performance
allowedStyleValues: 'somewhat-strict-web', // if targeting only web
},
})
// in other files use this:
console.log(`config is`, getConfig())
// get typescript types on @tamagui/core imports:
type AppConfig = typeof config
declare module '@tamagui/core' {
interface TamaguiCustomConfig extends AppConfig {}
}
Note that Tamagui maps tokens to style props using some logic, so if you use
<View margin="$sm /> it looks for
createTamagui({ tokens: { space: { sm: 10 } } }):
// if not specified it defaults to `space`
export const tokenCategories = {
radius: {
borderRadius: true,
borderTopLeftRadius: true,
borderTopRightRadius: true,
borderBottomLeftRadius: true,
borderBottomRightRadius: true,
borderStartStartRadius: true,
borderStartEndRadius: true,
borderEndStartRadius: true,
borderEndEndRadius: true,
},
size: {
width: true,
height: true,
minWidth: true,
minHeight: true,
maxWidth: true,
maxHeight: true,
blockSize: true,
minBlockSize: true,
maxBlockSize: true,
inlineSize: true,
minInlineSize: true,
maxInlineSize: true,
},
zIndex: {
zIndex: true,
},
color: {
backgroundColor: true,
borderColor: true,
borderBlockStartColor: true,
borderBlockEndColor: true,
borderBlockColor: true,
borderBottomColor: true,
borderInlineColor: true,
borderInlineStartColor: true,
borderInlineEndColor: true,
borderTopColor: true,
borderLeftColor: true,
borderRightColor: true,
borderEndColor: true,
borderStartColor: true,
shadowColor: true,
...textColors,
...(process.env.TAMAGUI_TARGET === 'web' && {
outlineColor: true,
caretColor: true,
}),
},
}
Tamagui themes are special and can do a lot, just know that you can generate them a few ways.
Simply just like above, or using our new createThemes from
@tamagui/config/v5.
It's done like this:
import * as Colors from '@tamagui/colors'
import { createThemes, defaultComponentThemes } from '@tamagui/config/v5'
const darkPalette = [
'#050505',
'#151515',
'#191919',
'#232323',
'#282828',
'#323232',
'#424242',
'#494949',
'#545454',
'#626262',
'#a5a5a5',
'#fff',
]
const lightPalette = [
'#fff',
'#f8f8f8',
'hsl(0, 0%, 96.3%)',
'hsl(0, 0%, 94.1%)',
'hsl(0, 0%, 92.0%)',
'hsl(0, 0%, 90.0%)',
'hsl(0, 0%, 88.5%)',
'hsl(0, 0%, 81.0%)',
'hsl(0, 0%, 56.1%)',
'hsl(0, 0%, 50.3%)',
'hsl(0, 0%, 42.5%)',
'hsl(0, 0%, 9.0%)',
]
const lightShadows = {
shadow1: 'rgba(0,0,0,0.04)',
shadow2: 'rgba(0,0,0,0.08)',
shadow3: 'rgba(0,0,0,0.16)',
shadow4: 'rgba(0,0,0,0.24)',
shadow5: 'rgba(0,0,0,0.32)',
shadow6: 'rgba(0,0,0,0.4)',
}
const darkShadows = {
shadow1: 'rgba(0,0,0,0.2)',
shadow2: 'rgba(0,0,0,0.3)',
shadow3: 'rgba(0,0,0,0.4)',
shadow4: 'rgba(0,0,0,0.5)',
shadow5: 'rgba(0,0,0,0.6)',
shadow6: 'rgba(0,0,0,0.7)',
}
const extraColors = {
black1: darkPalette[0],
black2: darkPalette[1],
black3: darkPalette[2],
black4: darkPalette[3],
black5: darkPalette[4],
black6: darkPalette[5],
black7: darkPalette[6],
black8: darkPalette[7],
black9: darkPalette[8],
black10: darkPalette[9],
black11: darkPalette[10],
black12: darkPalette[11],
white1: lightPalette[0],
white2: lightPalette[1],
white3: lightPalette[2],
white4: lightPalette[3],
white5: lightPalette[4],
white6: lightPalette[5],
white7: lightPalette[6],
white8: lightPalette[7],
white9: lightPalette[8],
white10: lightPalette[9],
white11: lightPalette[10],
white12: lightPalette[11],
}
const generatedThemes = createThemes({
componentThemes: defaultComponentThemes,
base: {
palette: {
dark: darkPalette,
light: lightPalette,
},
// for values we don't want being inherited onto sub-themes
extra: {
light: {
...Colors.blue,
...Colors.green,
...Colors.red,
...Colors.yellow,
...lightShadows,
...extraColors,
shadowColor: lightShadows.shadow1,
},
dark: {
...Colors.blueDark,
...Colors.greenDark,
...Colors.redDark,
...Colors.yellowDark,
...darkShadows,
...extraColors,
shadowColor: darkShadows.shadow1,
},
},
},
// inverse accent theme
accent: {
palette: {
dark: lightPalette,
light: darkPalette,
},
},
childrenThemes: {
blue: {
palette: {
dark: Object.values(Colors.blueDark),
light: Object.values(Colors.blue),
},
},
red: {
palette: {
dark: Object.values(Colors.redDark),
light: Object.values(Colors.red),
},
},
yellow: {
palette: {
dark: Object.values(Colors.yellowDark),
light: Object.values(Colors.yellow),
},
},
green: {
palette: {
dark: Object.values(Colors.greenDark),
light: Object.values(Colors.green),
},
},
},
})
export type TamaguiThemes = typeof generatedThemes
/**
* This is an optional production optimization: themes JS can get to 20Kb or more.
* Tamagui has ~1Kb of logic to hydrate themes from CSS, so you can remove the JS.
* So long as you server render your Tamagui CSS, this will save you bundle size:
*/
export const themes: TamaguiThemes =
process.env.TAMAGUI_ENVIRONMENT === 'client' && process.env.NODE_ENV === 'production'
? {}
: (generatedThemes as any)
And it generates a whole bunch of themes for you that are very nice like light, light_accent, light_accent_Button, etc. For more, see the config-v4.mdx file in search.