Tamagui: Bridging Web and Mobile Development

2j2e 9 views 40 slides Oct 28, 2025
Slide 1
Slide 1 of 40
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38
Slide 39
39
Slide 40
40

About This Presentation

In this session, we'll explore Tamagui, a powerful platform that enables you to write, style, and optimize code that runs seamlessly across web and mobile platforms. With its own abstract component library and robust support for design token systems, Tamagui empowers developers to create univers...


Slide Content

Eugene Zharkov
TAMAGUI
Bridging Web and Mobile Development
1

Content
•Design Tokens System
•Configuration
•Components System
•Animations
•Optimization
2

Opinionated but Flexible
my opinion
3

Pie
Simplified. Oversimplified.
reactreact-native
react-native-
web
tamagui
expo
Webpack
Vite
Metro
Next.js
!
One
!
!
!
!
!
!
!
!
!
4

Design Tokens
Image source: Medium article
5

Design Tokens
Image source: Figma6

Design Tokens
Figma
Image source: Figma7

Design Tokens
Example
"tabBar": {
“color”: "#efefef",
"colorLabelActive": "#ff0099",
"colorLabelDefault": "#aa9900",


"sizeSmallGap": 8,
"sizeSmallHeight": 40,
"sizeSmallHorizontalPadding": 8,
"sizeSmallVerticalPadding": 4

"sizeMediumGap": 4,
"sizeMediumHeight": 50,
"sizeMediumHorizontalPadding": 12,
"sizeMediumVerticalPadding": 6,
}
8

Tamagui Configuration
Provider
const config = createTamagui({
fonts: {},
animations: {},
themes: {},
tokens: {
color: {},
size: {},
space: {},
radius: {},
zIndex: {},
...
},
media: {},
});
import tamaguiConfig from "./tamagui.config";
export default function RootLayout() {
return (
<TamaguiProvider config={tamaguiConfig}>
<Stack>
<Stack.Screen name=“index" >
<Stack.Screen name="+not-found" >
<Stack>
<TamaguiProvider>
);
}
9

Breakpoints
MDSM LG X-LG
10

Breakpoints / Media
export default createTamagui({
media: {
sm: { maxWidth: 480 },
md: { maxWidth: 769 },
lg: { maxWidth: 1025 },
},
})
11

Breakpoints / Media
Order is important
export default createTamagui({
media: {
sm: { maxWidth: 480 },
gtSm: { minWidth: 480 + 1 },
md: { maxWidth: 769 },
gtMd: { minWidth: 769 + 1 },
},
})
12

Media
media: {
sm: { maxWidth: 480 },
gtSm: { minWidth: 480 + 1 },
md: { maxWidth: 769 },
gtMd: { minWidth: 769 + 1 },
lg: { maxWidth: 1025 },
gtLg: { minWidth: 1025 + 1 },
},
<XStack
backgroundColor="red"
$gtSm={{
backgroundColor: 'blue',
}}
$gtMd={{
backgroundColor: 'green',
}}
>
<Button onPress={…}>
Action
<Button>
<XStack>
13

Components
•XStack, YStack, ZStack
•H1, H2, H3, H4, H5, H6, Paragraph, SizableText, Text
•Button, Checkbox, Form, Input, TextArea, Label, Progress, RadioGroup, Select, Slider, Switch,
ToggleGroup
•AlertDialog, Dialog, Popover, Sheet, Tooltip, Toast
•Accordion, Group, Tabs
•Avatar, Card, Image, ListItem
•LinearGradient, Separator, Square, Circle
•Anchor, Section, Article, Main, Header, Aside, Footer, Nav, ScrollView, Spinner, Unspaced,
VisuallyHidden
14

Components
Sign Up Example
<YStack width="100%" maxWidth={400} margin="auto">
<Text fontWeight="bold" textAlign="center">
Register
<Text>
<Label htmlFor="name">Name<Label>
<Input
id="name"
placeholder="Enter your name"
value={formData.name}
onChangeText={(text) => handleChange("name", text)}
>
……
<Button onPress={handleSubmit}>
Register
<Button>
<YStack>
15

Custom Components
Label
const StyledComponent = styled(Label, {
name: "StyledLabel",
theme values
color: "$labelColor",
or direct values
fontSize: 20,
hoverStyle: {
color: "$labelColorHover",
},
});
export const StyledLabel:
FC<StyledLabelProps> = ({ htmlFor, children
}) => (
<StyledComponent htmlFor={htmlFor}>
{children}
<StyledComponent>
);
const config = createTamagui({
...
tokens: {
color: {
labelColor: "#333",
labelColorHover: "#555",
},
size: {},
space: {},
...
16

Custom Components
Button
const ButtonFrame = styled(Button, {

backgroundColor: ‘$primaryBackgroundColor’ ,
borderColor: '$primaryBorderColor' ,
hoverStyle: {
backgroundColor: '$primaryBackgroundHoverColor' ,
borderColor: '$primaryBorderHoverColor' ,
},
pressStyle: {
backgroundColor: '$primaryHoverColorPress' ,
borderColor: '$primaryBorderColorPress' ,
},
disabledStyle: {
backgroundColor: '$primaryBackgroundColorDisabled' ,
borderColor: '$primaryBorderColorDisabled' ,
},
17

Custom Components
Variants
const ButtonFrame = styled(Button, {
pressTheme: true,
variants: {
variant: {
primary: {
backgroundColor: ‘$primaryBackgroundColor’ ,
borderColor: '$primaryBorderColor' ,
hoverStyle: {
backgroundColor: '$primaryBackgroundHoverColor' ,
borderColor: '$primaryBorderHoverColor' ,
},
pressStyle: {
backgroundColor: '$primaryHoverColorPress' ,
borderColor: '$primaryBorderColorPress' ,
},
disabledStyle: {
backgroundColor: '$primaryBackgroundColorDisabled' ,
borderColor: '$primaryBorderColorDisabled' ,
},
secondary: {
backgroundColor: ‘…’,
borderColor: ‘…’,
hoverStyle: {
backgroundColor: ‘…’,
borderColor: ‘…’,
},
pressStyle: {
backgroundColor: ‘…’,
borderColor: ‘…’,
},
disabledStyle: {
backgroundColor: ‘…’,
borderColor: ‘…’,
},
18

Custom Components
Variants
toggled: {
true: {
backgroundColor: '$someColor1',
borderColor: '$someColor2',
},
},
elevated: {
true: {
isWeb ? {
boxShadow: '0px 0px 12px 0px #f0f’,
} : {
elevation: ..,
shadowOffset: { width: .., height: .. },
shadowOpacity: ..,
shadowRadius: ..,
}
},
},
<Button variant="primary" elevated>
Save
<Button>

——- OR ——-
<Button variant="secondary" toggled>
Dark Theme
<Button>
Use
19

Variants
Order
size: {
small: {
backgroundColor: ‘red’,
padding: 12
},
},
noBorders: {
true: {
padding: 0
},
},
20

Variants
Order
<Button size="small" noBorders … >
is not equal

<Button noBorders size="small" … >
21

Custom Components
Variants
size: {
lg: {
fontSize: '$lg',
padding: '$lg',
height: '$lg',
},
md: {
fontSize: '$md',
padding: '$md',
height: ‘$md',
},
sm: {
fontSize: ‘$sm',
padding: '$sm',
height: '$sm',
Alternative
size: {
'...size': (size, { tokens, font }) => {
return {
margin: tokens.space[size],
padding: tokens.size[size],
height: tokens.size[size],
lineHeight: font?.lineHeight,
}
},
},
22

Custom Components
Variants
const SizedText = styled(Text, {
variants: {
size: {
md: {
fontSize: '$sm',
$gtMd: {
fontSize: '$md',
},
$gt2xl: {
fontSize: '$lg',
},
},
<SizedText size="$md">Some Text<SizedText>

23

Shorthands
const shorthands = {
ac: 'alignContent',
ai: 'alignItems',
als: 'alignSelf',
bblr: 'borderBottomLeftRadius' ,
bbrr: 'borderBottomRightRadius' ,
bg: 'backgroundColor',
br: 'borderRadius',
btlr: 'borderTopLeftRadius' ,
btrr: 'borderTopRightRadius' ,
} as const
export default createTamagui({
shorthands,
})
<View
br={10}
bbrr={2}
ai="center"
ac="center"
>
24

Tokens
Sizes Space
25

Fonts
const robotoFont = createFont({
family: 'Roboto, "Helvetica Neue", sans-
serif',
size: {
1: 12,
2: 14,

6: 24,
7: 28,
},
weight: {
3: '300',
4: '400',

7: '700',
8: '800',
},
...
face: {
400: { normal: 'Roboto-Regular' },
600: { normal: 'Roboto-Semi' },
700: { normal: ‘Roboto-Bold' },
},
});
26

Fonts
<Text fontSize="$5" lineHeight="$1" fontFamily="$roboto" color="$white">
I need to think about it
<Text>
27

Themes
const config = createTamagui({
themes: {
light: {
labelColor: "#333",
labelColorHover: "#555",
},
dark: {
labelColor: "#fff",
labelColorHover: "#ddd",
},
},

<TamaguiProvider
config={tamaguiConfig}
defaultTheme="light">
<App >
<TamaguiProvider>
28

Themes
Isolation
<View>
<Theme name="dark">
<Button>I have the theme dark<Button>
<Theme>
<Theme name="pink">
<Button>I have the theme pink-dark<Button>
<Theme>
<View>
29

Animations
I 'creatively acquired' this bullet list
•Animate any style prop with animation config per-prop.
•Can animate across all states (media queries, hover, etc).
•Three drivers you can swap out with type safety.
•@tamagui/animations-css,
•@tamagui/animations-react-native
•@tamagui/animations-moti
•SSR safe mount animations.
•Enter and exit animations with AnimatePresence.
30

Animations
<Square
borderColor="$borderColor"
animation="bouncy"
elevation="$4"
backgroundColor="$color9"
size={104}
borderRadius="$9"
hoverStyle={{
scale: 1.2,
}}
pressStyle={{
scale: 0.9,
}}
>
<LogoIcon >
<Square>
31

Animations
Oh..Hi there!
<Square
borderColor="$borderColor"
animation="bouncy"
...
enterStyle={{
scale: 1.5,
y: -10,
opacity: 0,
}}
>
<LogoIcon >
<Square>
32

Animations
Leaving the scene
<AnimatePresence>
<Square
animation="bouncy"
...
enterStyle={{
opacity: 0,
y: 10,
}}
exitStyle={{
opacity: 0,
y: -10,
}}
>
<LogoIcon downscale={0.75} >
<Square>
<AnimatePresence>
33

@tamagui/static
•Extracts all types of styling syntax into atomic CSS.
•Removes a high % of inline styles with partial evaluation
and hoisting.
•Reduces tree depth, flattening expensive styled
components into div or View.
•Evaluates useMedia and useTheme hooks, turning logical
expressions into media queries and CSS variables.
34

@tamagui/static
Source
const Container = (props) => (
<View px="$2" w={550} $gtSm={{ px: '$6' }}>
<Heading size={props.big ? 'large' : ‘small'}>Text example<Heading>
<View>
)
35

@tamagui/static
JS
export const Container = props => <div className={_cn}>
<h1 className={_cn2 + (_cn3 + (props.big ? _cn4 : _cn5))}>
Text example
<h1>
<div>

const _cn5 = " _fos-16px"
const _cn4 = " _fos-22px"
const _cn3 = " _bg-180kg62 _col-b5vn3b _mt-0px _mr-0px _mb-0px _ml-0px _ww-break-word _bxs-
border-box _ff-System _dsp-inline "
const _cn2 = " font_System"
const _cn = " is_View _fd-column _miw-0px _mih-0px _pos-relative _bxs-border-box _fb-auto
_dsp-flex _fs-0 _ai-stretch _w-550px _pr-1aj14ca _pl-1aj14ca _pr-_gtSm_lrpixp _pl-
_gtSm_lrpixp"
36

@tamagui/static
CSS
._fd-column{flex-direction:column;}
._miw-0px{min-width:0px;}
._mih-0px{min-height:0px;}
._pos-relative{position:relative;}
._bxs-border-box{box-sizing:border-box;}
._fb-auto{flex-basis:auto;}
._dsp-flex{display:flex;}
._fs-0{flex-shrink:0;}
._ai-stretch{align-items:stretch;}
._w-550px{width:550px;}
._pr-1aj148u{padding-right:var(--space-3);}
._pl-1aj148u{padding-left:var(--space-3);}
@media (min-width: 801px) { :root:root ._pr-_gtSm_1aj14ca{padding-right:var(--space-7);} }
@media (min-width: 801px) { :root:root ._pl-_gtSm_1aj14ca{padding-left:var(--space-7);} }
._ml-0px{margin-left:0px;}
._mb-0px{margin-bottom:0px;}
._mr-0px{margin-right:0px;}
37

Pros
•Provides seamless cross-platform components that look and feel native on
both web and mobile.
•Focused on optimization.
•Offers robust theming support with dynamic color schemes and dark mode
out-of-the-box.
•Developer Productivity. Simplifies UI development with reusable, customizable
components.
•Fully supports TypeScript, ensuring type safety and better developer
experience.
38

Cons
•Learning Curve. The beginning lacks momentum
•You should understand all the framework's features to determine the best
approach
•Flexibility can lead to inconsistency in patterns. Your team should align to stay
on the same wavelength
•Documentation has made significant progress but remains unstructured or
ambiguous in some areas (you can fix it)
•The source code is somewhat complex
39

40