Tamagui
Tamagui is a complete UI solution for React Native and Web, with a fully-featured UI kit, styling engine, and optimizing compiler.
Tamagui Complete Documentation
Tamagui is a complete UI solution for React Native and Web, with a fully-featured UI kit, styling engine, and optimizing compiler.
components/accordion/1.0.0
title: Accordion description: A vertically stacked set of interactive headings with content. name: accordion component: Accordion package: accordion
<Highlights features={[ 'Full keyboard navigation.', 'Can expand one or multiple items.', 'Can be controlled or uncontrolled.', ]} />
Installation
Accordion is already installed in tamagui, or you can install it independently:
npm install @tamagui/accordion
Anatomy
Import all parts and piece them together.
import { Accordion } from 'tamagui' // or '@tamagui/accordion'
export default () => (
<Accordion>
<Accordion.Item>
<Accordion.Header>
<Accordion.Trigger />
</Accordion.Header>
<Accordion.Content />
</Accordion.Item>
</Accordion>
)
API Reference
Accordion
Contains all the parts of an accordion.
<PropsTable data={[ { name: 'asChild', required: false, type: 'boolean', default: 'false', description: 'Change the component to the HTML tag or custom component of the only child. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.', }, { name: 'type', required: true, type: '"single" | "multiple"', typeSimple: 'enum', description: ( Determines whether one or multiple items can be opened at the same time. ), }, { name: 'value', required: false, type: 'string', description: ( The controlled value of the item to expand when type is{' '} "single". Must be used in conjunction with{' '} onValueChange. ), }, { name: 'defaultValue', required: false, type: 'string', description: ( The value of the item to expand when initially rendered and type is{' '} "single". Use when you do not need to control the state of the items. ), }, { name: 'onValueChange', required: false, type: '(value: string) => void', typeSimple: 'function', description: ( Event handler called when the expanded state of an item changes and{' '} type is "single". ), }, { name: 'value', required: false, default: '[]', type: 'string[]', description: ( The controlled value of the item to expand when type is{' '} "multiple". Must be used in conjunction with{' '} onValueChange. ), }, { name: 'defaultValue', required: false, default: '[]', type: 'string[]', description: ( The value of the item to expand when initially rendered when type{' '} is "multiple". Use when you do not need to control the state of the items. ), }, { name: 'onValueChange', required: false, type: '(value: string[]) => void', typeSimple: 'function', description: ( Event handler called when the expanded state of an item changes and{' '} type is "multiple". ), }, { name: 'collapsible', required: false, default: 'false', type: 'boolean', description: ( When type is "single", allows closing content when clicking trigger for an open item. ), }, { name: 'disabled', required: false, type: 'boolean', default: 'false', description: ( When true, prevents the user from interacting with the accordion and all its items. ), }, { name: 'dir', required: false, type: '"ltr" | "rtl"', typeSimple: 'enum', default: '"ltr"', description: 'The reading direction of the accordion when applicable. If omitted, assumes LTR (left-to-right) reading mode.', }, ]} />
Item
Contains all the parts of a collapsible section.
<PropsTable data={[ { name: 'asChild', required: false, type: 'boolean', default: 'false', description: 'Change the component to the HTML tag or custom component of the only child. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.', }, { name: 'disabled', required: false, type: 'boolean', default: 'false', description: ( When true, prevents the user from interacting with the item. ), }, { name: 'value', required: true, type: 'string', description: 'A unique value for the item.', }, ]} />
Header
Wraps an Accordion.Trigger. Use the asChild prop to update it to the appropriate heading level for your page.
<PropsTable data={[ { name: 'asChild', required: false, type: 'boolean', default: 'false', description: 'Change the component to the HTML tag or custom component of the only child. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.', }, ]} />
Trigger
Toggles the collapsed state of its associated item. It should be nested inside of an Accordion.Header.
<PropsTable data={[ { name: 'asChild', required: false, type: 'boolean', default: 'false', description: 'Change the component to the HTML tag or custom component of the only child. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.', }, ]} />
Content
Contains the collapsible content for an item.
<PropsTable data={[ { name: 'asChild', required: false, type: 'boolean', default: 'false', description: 'Change the component to the HTML tag or custom component of the only child. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.', }, { name: 'forceMount', type: 'boolean', description: ( Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries. ), }, ]} />
Examples
Expanded by default
Use the defaultValue prop to define the open item by default.
<Accordion type="single" __defaultValue__="item-2">
<Accordion.Item value="item-1">…</Accordion.Item>
<Accordion.Item value="item-2">…</Accordion.Item>
</Accordion>
Allow collapsing all items
Use the collapsible prop to allow all items to close.
<Accordion type="single" __collapsible__>
<Accordion.Item value="item-1">…</Accordion.Item>
<Accordion.Item value="item-2">…</Accordion.Item>
</Accordion>
Multiple items open at the same time
Set the type prop to multiple to enable opening multiple items at once.
<Accordion type="__multiple__">
<Accordion.Item value="item-1">…</Accordion.Item>
<Accordion.Item value="item-2">…</Accordion.Item>
</Accordion>
Accessibility
Adheres to the Accordion WAI-ARIA design pattern.
components/accordion/2.0.0
title: Accordion description: A vertically stacked set of interactive headings with content name: accordion component: Accordion package: accordion demoName: Accordion
<Highlights features={[ 'Full keyboard navigation.', 'Can expand one or multiple items.', 'Can be controlled or uncontrolled.', ]} />
Installation
Accordion is already installed in tamagui, or you can install it independently:
npm install @tamagui/accordion
Anatomy
Import all parts and piece them together.
import { Accordion } from 'tamagui' // or '@tamagui/accordion'
export default () => (
<Accordion>
<Accordion.Item>
<Accordion.Header>
<Accordion.Trigger />
</Accordion.Header>
<Accordion.Content />
</Accordion.Item>
</Accordion>
)
API Reference
Accordion
Contains all the parts of an accordion.
<PropsTable data={[ { name: 'asChild', required: false, type: 'boolean', default: 'false', description: 'Change the component to the HTML tag or custom component of the only child. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.', }, { name: 'type', required: true, type: '"single" | "multiple"', typeSimple: 'enum', description: ( Determines whether one or multiple items can be opened at the same time. ), }, { name: 'value', required: false, type: 'string', description: ( The controlled value of the item to expand when type is{' '} "single". Must be used in conjunction with{' '} onValueChange. ), }, { name: 'defaultValue', required: false, type: 'string', description: ( The value of the item to expand when initially rendered and type is{' '} "single". Use when you do not need to control the state of the items. ), }, { name: 'onValueChange', required: false, type: '(value: string) => void', typeSimple: 'function', description: ( Event handler called when the expanded state of an item changes and{' '} type is "single". ), }, { name: 'value', required: false, default: '[]', type: 'string[]', description: ( The controlled value of the item to expand when type is{' '} "multiple". Must be used in conjunction with{' '} onValueChange. ), }, { name: 'defaultValue', required: false, default: '[]', type: 'string[]', description: ( The value of the item to expand when initially rendered when type{' '} is "multiple". Use when you do not need to control the state of the items. ), }, { name: 'onValueChange', required: false, type: '(value: string[]) => void', typeSimple: 'function', description: ( Event handler called when the expanded state of an item changes and{' '} type is "multiple". ), }, { name: 'collapsible', required: false, default: 'false', type: 'boolean', description: ( When type is "single", allows closing content when clicking trigger for an open item. ), }, { name: 'disabled', required: false, type: 'boolean', default: 'false', description: ( When true, prevents the user from interacting with the accordion and all its items. ), }, { name: 'dir', required: false, type: '"ltr" | "rtl"', typeSimple: 'enum', default: '"ltr"', description: 'The reading direction of the accordion when applicable. If omitted, assumes LTR (left-to-right) reading mode.', }, ]} />
Accordion.Item
Contains all the parts of a collapsible section.
<PropsTable data={[ { name: 'asChild', required: false, type: 'boolean', default: 'false', description: 'Change the component to the HTML tag or custom component of the only child. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.', }, { name: 'disabled', required: false, type: 'boolean', default: 'false', description: ( When true, prevents the user from interacting with the item. ), }, { name: 'value', required: true, type: 'string', description: 'A unique value for the item.', }, ]} />
Accordion.Header
Wraps an Accordion.Trigger. Use the asChild prop to update it to the appropriate heading level for your page.
<PropsTable data={[ { name: 'asChild', required: false, type: 'boolean', default: 'false', description: 'Change the component to the HTML tag or custom component of the only child. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.', }, ]} />
Accordion.Trigger
Toggles the collapsed state of its associated item. It should be nested inside of an Accordion.Header.
<PropsTable data={[ { name: 'asChild', required: false, type: 'boolean', default: 'false', description: 'Change the component to the HTML tag or custom component of the only child. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.', }, ]} />
Accordion.Content
Contains the collapsible content for an item.
<PropsTable data={[ { name: 'asChild', required: false, type: 'boolean', default: 'false', description: 'Change the component to the HTML tag or custom component of the only child. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.', }, { name: 'forceMount', type: 'boolean', description: ( Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries. ), }, ]} />
Examples
Expanded by default
Use the defaultValue prop to define the open item by default.
<Accordion type="single" __defaultValue__="item-2">
<Accordion.Item value="item-1">…</Accordion.Item>
<Accordion.Item value="item-2">…</Accordion.Item>
</Accordion>
Allow collapsing all items
Use the collapsible prop to allow all items to close.
<Accordion type="single" __collapsible__>
<Accordion.Item value="item-1">…</Accordion.Item>
<Accordion.Item value="item-2">…</Accordion.Item>
</Accordion>
Multiple items open at the same time
Set the type prop to multiple to enable opening multiple items at once.
<Accordion type="__multiple__">
<Accordion.Item value="item-1">…</Accordion.Item>
<Accordion.Item value="item-2">…</Accordion.Item>
</Accordion>
Accessibility
Adheres to the Accordion WAI-ARIA design pattern.
components/alert-dialog/1.0.0
title: AlertDialog description: Show an alert prompt in a dialog name: alertDialog component: AlertDialog package: alert-dialog demoName: AlertDialog
<Highlights
features={[
Comes with styling, completely customizable and themeable.,
Accepts animations, themes, size props and more.,
Accessible with dev-time checks to ensure ARIA props.,
]}
/>
Installation
Alert Dialog is already installed in tamagui, or you can install it independently:
npm install @tamagui/alert-dialog
In order to use this component independently of tamagui, you'll first need to install the @tamagui/portal package:
npm install @tamagui/portal
Then add PortalProvider to the root of your app:
import { PortalProvider } from '@tamagui/portal'
import YourApp from './components/YourApp'
function App() {
return (
<PortalProvider shouldAddRootHost>
<YourApp />
</PortalProvider>
)
}
export default App
Anatomy
import { AlertDialog } from 'tamagui' // or '@tamagui/alert-dialog'
export default () => (
<AlertDialog>
<AlertDialog.Trigger />
<AlertDialog.Portal>
<AlertDialog.Overlay />
<AlertDialog.Content>
<AlertDialog.Title />
<AlertDialog.Description />
<AlertDialog.Cancel />
{/* ... */}
</AlertDialog.Content>
</AlertDialog.Portal>
</AlertDialog>
)
API Reference
AlertDialog
Contains every component for the AlertDialog. Shares all Dialog Props, except modal which is on by default. Adds:
<PropsTable
data={[
{
name: 'native',
type: 'boolean',
required: false,
description: When true, on iOS it will render as a native AlertDialog.,
},
]}
/>
AlertDialog.Trigger
Just Tamagui Props.
AlertDialog.Portal
Renders AlertDialog into appropriate container. Beyond Tamagui Props, adds:
<PropsTable
data={[
{
name: 'forceMount',
type: 'boolean',
required: false,
description: Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries.,
},
]}
/>
AlertDialog.Content
Main container for AlertDialog content, this is where you should apply animations.
Beyond Tamagui Props, adds:
<PropsTable
data={[
{
name: 'forceMount',
type: 'boolean',
required: false,
description: Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries.,
},
]}
/>
AlertDialog.Overlay
Displays behind Content. Beyond Tamagui Props, adds:
<PropsTable
data={[
{
name: 'forceMount',
type: 'boolean',
required: false,
description: Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries.,
},
]}
/>
AlertDialog.Title
Required. Can wrap in VisuallyHidden to hide.
Defaults to H2, see Headings.
AlertDialog.Description
Required. Can wrap in VisuallyHidden to hide.
Defaults to Paragraph, see Paragraph.
AlertDialog.Cancel
Closes the AlertDialog, accepts all YStack props. Recommended to use with your own component and asChild.
<PropsTable
data={[
{
name: 'displayWhenAdapted',
type: 'boolean',
description: By default Cancel elements hide when Adapt is active. If set to true, they will show when adapted.,
},
]}
/>
PortalProvider
<PropsTable
data={[
{
name: 'shouldAddRootHost',
type: 'boolean',
required: false,
description: Defines whether to add a default root host or not.,
},
]}
/>
Examples
Inside native modals
If you're using native modals (maybe from react-navigation), you'll notice the Dialogs won't show up inside the modal. To get around this, you should wrap your screen inside PortalProvider, like so:
import { PortalProvider } from 'tamagui'
// this component used in react-navigation/expo-router with `presentation: "modal"`
export function Page() {
return (
<PortalProvider>{/* rest of your page, including the Dialog... */}</PortalProvider>
)
}
components/alert-dialog/2.0.0
title: Alert Dialog description: Show an alert prompt in a dialog name: alert-dialog component: AlertDialog package: alert-dialog demoName: AlertDialog
<Highlights
features={[
Comes with styling, completely customizable and themeable.,
Accepts animations, themes, size props and more.,
Accessible with dev-time checks to ensure ARIA props.,
]}
/>
AlertDialog is a modal dialog that interrupts the user with important content and expects a response. It's built on Dialog with stricter accessibility requirements, and automatically stacks above other content.
Installation
Alert Dialog is already installed in tamagui, or you can install it independently:
npm install @tamagui/alert-dialog
Anatomy
import { AlertDialog } from 'tamagui' // or '@tamagui/alert-dialog'
export default () => (
<AlertDialog>
<AlertDialog.Trigger />
<AlertDialog.Portal>
<AlertDialog.Overlay />
<AlertDialog.Content>
<AlertDialog.Title />
<AlertDialog.Description />
<AlertDialog.Cancel />
{/* ... */}
</AlertDialog.Content>
</AlertDialog.Portal>
</AlertDialog>
)
API Reference
AlertDialog
Contains every component for the AlertDialog. Shares all Dialog Props, except modal which is on by default. Adds:
<PropsTable
data={[
{
name: 'native',
type: 'boolean',
required: false,
description: When true, on iOS it will render as a native AlertDialog.,
},
]}
/>
AlertDialog.Trigger
Just Tamagui Props.
AlertDialog.Portal
Renders AlertDialog into appropriate container. Beyond Tamagui Props, adds:
<PropsTable
data={[
{
name: 'forceMount',
type: 'boolean',
required: false,
description: Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries.,
},
]}
/>
AlertDialog.Content
Main container for AlertDialog content, this is where you should apply animations.
Beyond Tamagui Props, adds:
<PropsTable
data={[
{
name: 'forceMount',
type: 'boolean',
required: false,
description: Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries.,
},
]}
/>
AlertDialog.Overlay
Displays behind Content. Beyond Tamagui Props, adds:
<PropsTable
data={[
{
name: 'forceMount',
type: 'boolean',
required: false,
description: Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries.,
},
]}
/>
AlertDialog.Title
Required. Can wrap in VisuallyHidden to hide.
Defaults to H2, see Headings.
AlertDialog.Description
Required. Can wrap in VisuallyHidden to hide.
Defaults to Paragraph, see Paragraph.
AlertDialog.Cancel
Closes the AlertDialog, accepts all YStack props. Recommended to use with your own component and asChild.
<PropsTable
data={[
{
name: 'displayWhenAdapted',
type: 'boolean',
description: By default Cancel elements hide when Adapt is active. If set to true, they will show when adapted.,
},
]}
/>
AlertDialog.Action
Confirms the AlertDialog action, accepts all YStack props. Recommended to use with your own component and asChild.
<PropsTable
data={[
{
name: 'displayWhenAdapted',
type: 'boolean',
description: By default Action elements hide when Adapt is active. If set to true, they will show when adapted.,
},
]}
/>
AlertDialog.Destructive
A destructive action button for the AlertDialog. When using native mode on iOS, this renders with the native red destructive button style. Accepts all YStack props.
<AlertDialog native>
<AlertDialog.Trigger asChild>
<Button>Delete Account</Button>
</AlertDialog.Trigger>
<AlertDialog.Portal>
<AlertDialog.Overlay />
<AlertDialog.Content>
<AlertDialog.Title>Delete Account?</AlertDialog.Title>
<AlertDialog.Description>This action cannot be undone.</AlertDialog.Description>
<AlertDialog.Cancel asChild>
<Button>Cancel</Button>
</AlertDialog.Cancel>
<AlertDialog.Destructive asChild>
<Button theme="red">Delete</Button>
</AlertDialog.Destructive>
</AlertDialog.Content>
</AlertDialog.Portal>
</AlertDialog>
<PropsTable
data={[
{
name: 'displayWhenAdapted',
type: 'boolean',
description: By default Destructive elements hide when Adapt is active. If set to true, they will show when adapted.,
},
]}
/>
PortalProvider
<PropsTable
data={[
{
name: 'shouldAddRootHost',
type: 'boolean',
required: false,
description: Defines whether to add a default root host or not.,
},
]}
/>
components/anchor/1.0.0
title: Anchor description: Link to external websites. name: html component: Anchor
<Highlights features={['Supports SSR.', 'Works on native and web.', 'Accepts Tamagui style props.']} />
Usage
The Anchor component provides a way to link to external websites. It extends SizableText, adding the href, target, and rel attributes.
On native, it will use React Native Linking.openURL, on web it will render to an a element with href set appropriately.
API Reference
Anchor
Inherits Tamagui props as well as:
<PropsTable
data={[
{
name: 'href',
required: false,
type: 'string',
description: Location to link to.,
},
{
name: 'target',
required: false,
type: 'string',
},
{
name: 'rel',
required: false,
type: 'string',
},
]}
/>
components/anchor/2.0.0
title: Anchor description: Link to external websites name: anchor component: Anchor package: html
<Highlights features={['Supports SSR.', 'Works on native and web.', 'Accepts Tamagui style props.']} />
Installation
Anchor is already installed in tamagui, or you can install it independently:
npm install @tamagui/html
Usage
The Anchor component provides a way to link to external websites. It extends SizableText, adding the href, target, and rel attributes.
On native, it uses React Native Linking.openURL. On web, it renders an a element with href set appropriately.
API Reference
Anchor
Inherits Tamagui props as well as:
<PropsTable
data={[
{
name: 'href',
required: false,
type: 'string',
description: The URL to link to.,
},
{
name: 'target',
required: false,
type: 'string',
description: Specifies where to open the linked document.,
},
{
name: 'rel',
required: false,
type: 'string',
description: Specifies the relationship between the current document and the linked document.,
},
]}
/>
components/avatar/1.0.0
title: Avatar description: Display aspect-fixed images with a fallback while loading name: avatar component: Avatar package: avatar demoName: Avatar
<Highlights features={[ 'Accepts size prop that stays in sync with other components.', 'Completely control styles on every element.', 'Automatically swaps fallback for image on load.', ]} />
Installation
Avatar is already installed in tamagui, or you can install it independently:
npm install @tamagui/avatar
Usage
import { Avatar } from 'tamagui'
export default () => (
<Avatar circular size="$6">
<Avatar.Image src="http://picsum.photos/200/300" />
<Avatar.Fallback bc="red" />
</Avatar>
)
API Reference
Avatar
Avatar extends Square, giving it all the Tamagui standard props as well as size and circular.
Avatar.Fallback
Avatar.Fallback extends YStack, plus:
<PropsTable
data={[
{
name: 'delayMs',
required: false,
type: 'number',
description: Milliseconds to wait before showing the fallback, to prevent flicker.,
},
]}
/>
Avatar.Image
Avatar.Image extends Image.
components/avatar/2.0.0
title: Avatar description: Display aspect-ratio-fixed images with a fallback while loading name: avatar component: Avatar package: avatar demoName: Avatar
<Highlights features={[ 'Accepts size prop that stays in sync with other components.', 'Completely control styles on every element.', 'Automatically swaps fallback for image on load.', ]} />
Installation
Avatar is already installed in tamagui, or you can install it independently:
npm install @tamagui/avatar
Usage
import { Avatar } from 'tamagui'
export default () => (
<Avatar circular size="$6">
<Avatar.Image src="http://picsum.photos/200/300" />
<Avatar.Fallback bc="red" />
</Avatar>
)
API Reference
Avatar
Avatar extends Square, giving it all the Tamagui standard props as well as size and circular.
Avatar.Fallback
Avatar.Fallback extends YStack, plus:
<PropsTable
data={[
{
name: 'delayMs',
required: false,
type: 'number',
description: Milliseconds to wait before showing the fallback, to prevent flicker.,
},
]}
/>
Avatar.Image
Avatar.Image extends Image.
components/button/1.0.0-alpha
title: Button description: A simple button component name: button component: Button demoName: Button
Button
A simple, sizable button.
<Highlights features={[ 'Accepts size prop that works on all styles.', 'Can inverse theme with themeInverse.', 'Place an icon before or after.', ]} />
Usage
import { Button } from 'tamagui'
export default () => <Button>Lorem ipsum</Button>
Sizing
Sizing buttons provides a unique challenge especially for a compiler, because
you need to adjust many different properties - not just on the outer frame, but
on the text wrapped inside. Tamagui supports adjusting the padding, border
radius, font size and icons sizes all in one with the size prop.
import { Button } from 'tamagui'
export default () => <Button size="$6">Lorem ipsum</Button>
Given your theme defines a size 6, the button will adjust all of the
properties appropriately. You can also pass a plain number to get an arbitrary
size.
Icon Theming
You can pass icons as either elements or components. If passing components,
Tamagui will automatically pass the size and color prop to them based on
your theme.
Button props
Button extends View, inheriting all the Tamagui standard props, adding:
<PropsTable
data={[
{
name: 'size',
required: false,
type: 'string | tokens.size',
description: Set a size, number or one of the size token values.,
},
{
name: 'theme',
required: false,
type: 'string',
description: Apply a theme just to the button and it's children,
},
{
name: 'themeInverse',
required: false,
type: 'boolean',
description: Helpful for "flipping" any theme between dark and light (including flipping a sub themes defined as [subtheme]-[dark/light],
},
{
name: 'textProps',
required: false,
type: 'TextProps',
description: By default a button wraps contents in Text and will pass textProps if set.,
},
{
name: 'noTextWrap',
required: false,
type: 'boolean',
description: If true, Button won't wrap content with a Text element.,
},
{
name: 'icon',
required: false,
type: 'JSX.Element',
description: Pass any React element, appears before the text.,
},
{
name: 'iconAfter',
required: false,
type: 'JSX.Element',
description: Pass any React element, appears after the text.,
},
]}
/>
components/button/1.0.0-beta.0
title: Button description: A simple button component name: button component: Button demoName: Button
Button
A simple, sizable button.
<Highlights features={[ 'Accepts size prop that works on all styles.', 'Can inverse theme with themeInverse.', 'Place an icon before or after.', ]} />
Usage
import { Button } from 'tamagui'
export default () => <Button>Lorem ipsum</Button>
Sizing
Sizing buttons provides a unique challenge especially for a compiler, because
you need to adjust many different properties - not just on the outer frame, but
on the text wrapped inside. Tamagui supports adjusting the padding, border
radius, font size and icons sizes all in one with the size prop.
import { Button } from 'tamagui'
export default () => <Button size="$6">Lorem ipsum</Button>
Given your theme defines a size 6, the button will adjust all of the
properties appropriately. You can also pass a plain number to get an arbitrary
size.
Icon Theming
You can pass icons as either elements or components. If passing components,
Tamagui will automatically pass the size and color prop to them based on
your theme.
Button props
Button extends View, inheriting all the Tamagui standard props, plus:
<PropsTable
data={[
{
name: 'size',
required: false,
type: 'string | tokens.size',
description: Set a size, number or one of the size token values.,
},
{
name: 'theme',
required: false,
type: 'string',
description: Apply a theme just to the button and it's children,
},
{
name: 'themeInverse',
required: false,
type: 'boolean',
description: Helpful for "flipping" any theme between dark and light (including flipping a sub themes defined as [subtheme]-[dark/light],
},
{
name: 'noTextWrap',
required: false,
type: 'boolean',
description: If true, Button won't wrap content with a Text element.,
},
{
name: 'icon',
required: false,
type: 'JSX.Element',
description: Pass any React element, appears before the text.,
},
{
name: 'iconAfter',
required: false,
type: 'JSX.Element',
description: Pass any React element, appears after the text.,
},
{
name: 'scaleIcon',
required: false,
type: 'number',
description: Scale the icon more than usual by this number.,
},
{
name: 'scaleSpace',
required: false,
type: 'number',
description: Scale the spacing more than usual by this number.,
},
{
name: 'spaceFlex',
required: false,
type: boolean,
description: Makes all space elements have a flex.,
},
{
name: 'color',
required: false,
type: SizableTextProps['color'],
description: Passes "color" down to the inner text component,
},
{
name: 'fontWeight',
required: false,
type: SizableTextProps['fontWeight'],
description: Passes "fontWeight" down to the inner text component,
},
{
name: 'letterSpacing',
required: false,
type: SizableTextProps['letterSpacing'],
description: Passes "letterSpacing" down to the inner text component,
},
{
name: 'textAlign',
required: false,
type: SizableTextProps['textAlign'],
description: Passes "textAlign" down to the inner text component,
},
]}
/>
components/button/1.0.0
title: Button description: A simple button component name: button component: Button package: button demoName: Button
Button
A simple, sizable button.
<Highlights features={[ 'Accepts size prop that works on all styles.', 'Can inverse theme with themeInverse.', 'Place an icon before or after.', ]} />
Usage
import { Button } from 'tamagui'
export default () => <Button>Lorem ipsum</Button>
Sizing
Sizing buttons provides a unique challenge especially for a compiler, because you need to adjust many different properties - not just on the outer frame, but on the text wrapped inside. Tamagui supports adjusting the padding, border radius, font size and icons sizes all in one with the size prop.
import { Button } from 'tamagui'
export default () => <Button size="$6">Lorem ipsum</Button>
Given your theme defines a size 6, the button will adjust all of the properties appropriately. You can also pass a plain number to get an arbitrary size.
Icon Theming
You can pass icons as either elements or components. If passing components, Tamagui will automatically pass the size and color prop to them based on your theme.
You can use the source of Button itself to see in more detail what variants you can override, and how we use this pattern internally to create our Button component.
Customization (Advanced)
Button only supports a limited subset of text props directly, and doesn't accept hoverStyle text props. If you need more control, you can do a simple customization using some exported helpers.
Please note that this pattern is a bit antithetical to the multiple-components APIs that Tamagui generally prefers. In a future release we hope to fix this, but that change should be easy to migrate to.
import { forwardRef } from 'react'
import {
ButtonFrame,
ButtonText,
GetProps,
ButtonProps as TamaguiButtonProps,
styled,
themeable,
useButton,
} from 'tamagui'
const CustomButtonFrame = styled(ButtonFrame, {
// ...
})
const CustomButtonText = styled(ButtonText, {
// ...
})
// to capture the custom variant types you define
type CustomButtonFrameProps = GetProps<typeof CustomButtonFrame>
type CustomButtonTextProps = GetProps<typeof CustomButtonText>
export type CustomButtonProps = TamaguiButtonProps &
CustomButtonFrameProps &
CustomButtonTextProps
export const Button = CustomButtonFrame.styleable<CustomButtonProps>((propsIn, ref) => {
const { props } = useButton(propsIn, { Text: CustomButtonText })
return <CustomButtonFrame {...props} ref={ref} />
})
Button props
Buttons extend Stack views inheriting all the Tamagui standard props, plus:
<PropsTable
data={[
{
name: 'size',
required: false,
type: 'string | tokens.size',
description: Set a size, number or one of the size token values.,
},
{
name: 'theme',
required: false,
type: 'string',
description: Apply a theme just to the button and it's children,
},
{
name: 'themeInverse',
required: false,
type: 'boolean',
description: Helpful for "flipping" any theme between dark and light (including flipping a sub themes defined as [subtheme]-[dark/light],
},
{
name: 'noTextWrap',
required: false,
type: 'boolean',
description: If true, Button won't wrap content with a Text element.,
},
{
name: 'icon',
required: false,
type: 'JSX.Element',
description: Pass any React element, appears before the text.,
},
{
name: 'iconAfter',
required: false,
type: 'JSX.Element',
description: Pass any React element, appears after the text.,
},
{
name: 'scaleIcon',
required: false,
type: 'number',
description: Scale the icon more than usual by this number.,
},
{
name: 'scaleSpace',
required: false,
type: 'number',
description: Scale the spacing more than usual by this number.,
},
{
name: 'spaceFlex',
required: false,
type: boolean,
description: Makes all space elements have a flex.,
},
{
name: 'color',
required: false,
type: SizableTextProps['color'],
description: Passes "color" down to the inner text component,
},
{
name: 'fontWeight',
required: false,
type: SizableTextProps['fontWeight'],
description: Passes "fontWeight" down to the inner text component,
},
{
name: 'letterSpacing',
required: false,
type: SizableTextProps['letterSpacing'],
description: Passes "letterSpacing" down to the inner text component,
},
{
name: 'textAlign',
required: false,
type: SizableTextProps['textAlign'],
description: Passes "textAlign" down to the inner text component,
},
{
name: 'circular',
required: false,
type: boolean,
description: Forces a circular button.,
},
{
name: 'unstyled',
required: false,
type: boolean,
description: Removes all default Tamagui styles.,
},
]}
/>
components/button/1.28.0
title: Button description: An incredibly flexible button. name: button component: Button package: button demoName: Button
<Highlights features={[ 'Accepts size prop that works on all styles.', 'Can inverse theme with themeInverse.', 'Place an icon before or after.', ]} />
Usage
When using the simple Button API, it's as simple as this:
import { Button } from 'tamagui'
export default () => <Button>Lorem ipsum</Button>
Sizing
Sizing buttons provides a unique challenge especially for a compiler, because you need to adjust many different properties - not just on the outer frame, but on the text wrapped inside. Tamagui supports adjusting the padding, border radius, font size and icons sizes all in one with the size prop.
import { Button } from 'tamagui'
export default () => <Button size="$6">Lorem ipsum</Button>
Given your theme defines a size 6, the button will adjust all of the properties appropriately. You can also pass a plain number to get an arbitrary size.
Icon Theming
You can pass icons as either elements or components. If passing components, Tamagui will automatically pass the size and color prop to them based on your theme.
You can use the source of Button itself to see in more detail what variants you can override, and how we use this pattern internally to create our Button component.
Creating your own Button
Tamagui now has all the features necessary to make creating a custom Button easy enough that you may want to roll your own button. Learn how to do it with our dedicated guide, How to Build a Button.
API Reference
Button
Buttons extend Stack views inheriting all the Tamagui standard props, plus:
<PropsTable
data={[
{
name: 'size',
required: false,
type: 'string | tokens.size',
description: Set a size, number or one of the size token values.,
},
{
name: 'theme',
required: false,
type: 'string',
description: Apply a theme just to the button and it's children,
},
{
name: 'themeInverse',
required: false,
type: 'boolean',
description: Helpful for "flipping" any theme between dark and light (including flipping a sub themes defined as [subtheme]-[dark/light],
},
{
name: 'noTextWrap',
required: false,
type: 'boolean',
description: If true, Button won't wrap content with a Text element.,
},
{
name: 'icon',
required: false,
type: 'JSX.Element',
description: Pass any React element, appears before the text.,
},
{
name: 'iconAfter',
required: false,
type: 'JSX.Element',
description: Pass any React element, appears after the text.,
},
{
name: 'scaleIcon',
required: false,
type: 'number',
description: Scale the icon more than usual by this number.,
},
{
name: 'scaleSpace',
required: false,
type: 'number',
description: Scale the spacing more than usual by this number.,
},
{
name: 'spaceFlex',
required: false,
type: boolean,
description: Makes all space elements have a flex.,
},
{
name: 'color',
required: false,
type: SizableTextProps['color'],
description: Passes "color" down to the inner text component,
},
{
name: 'fontWeight',
required: false,
type: SizableTextProps['fontWeight'],
description: Passes "fontWeight" down to the inner text component,
},
{
name: 'letterSpacing',
required: false,
type: SizableTextProps['letterSpacing'],
description: Passes "letterSpacing" down to the inner text component,
},
{
name: 'textAlign',
required: false,
type: SizableTextProps['textAlign'],
description: Passes "textAlign" down to the inner text component,
},
{
name: 'circular',
required: false,
type: boolean,
description: Forces a circular button.,
},
{
name: 'unstyled',
required: false,
type: boolean,
description: Removes all default Tamagui styles.,
},
]}
/>
components/button/2.0.0
title: Button description: A simple button component name: button component: Button package: button demoName: Button
<Highlights
features={[
'Size prop that works on all styles.',
'Place an icon before or after.',
'Control icon size explicitly with iconSize.',
'Theme groups of buttons with Button.Apply.',
]}
/>
Installation
Button is already installed in tamagui, or you can install it independently:
npm install @tamagui/button
Usage
import { Button } from 'tamagui'
export default () => <Button>Lorem ipsum</Button>
Sizing
Sizing buttons provides a unique challenge especially for a compiler, because
you need to adjust many different properties - not just on the outer frame, but
on the text wrapped inside. Tamagui supports adjusting the padding, border
radius, font size and icons sizes all in one with the size prop.
import { Button } from 'tamagui'
export default () => <Button size="$6">Lorem ipsum</Button>
Given your theme defines a size 6, the button will adjust all of the
properties appropriately. You can also pass a plain number to get an arbitrary
size.
Variants
The Button component supports different visual styles through the variant
prop. Currently, the primary available variant is "outlined".
import { Button, XStack } from 'tamagui'
export default () => (
<XStack gap="$2">
<Button>Default</Button>
<Button variant="outlined">Outlined</Button>
</XStack>
)
When variant="outlined" is applied, the button typically has a transparent
background with a visible border. The exact appearance (border color,
hover/press states) is determined by your theme's definitions for an outlined
button.
Icon Theming
You can pass icons as either elements or components. If passing components,
Tamagui will automatically theme them (passing size). The icon size is
determined by the Button's size prop by default.
You can also explicitly set the icon size using the iconSize prop, which
accepts a SizeTokens value (e.g., "$2"). The scaleIcon prop can be used to
further adjust the size relative to the determined or explicitly set icon size.
When an icon is present, Tamagui automatically adds spacing between the icon and
the button's text using the CSS gap property on the Button frame. The gap is
derived from the Button's size token value, keeping spacing consistent with
the overall button dimensions.
import { Button, Star } from 'tamagui'
export default () => (
<>
<Button icon={Star} size="$5">
Icon sized by Button
</Button>
<Button icon={Star} iconSize="$2" size="$5">
Icon sized explicitly
</Button>
</>
)
You can use the source of Button itself to see in more detail what variants you can override, and how we use this pattern internally to create our Button component.
Group Theming
You can use Button.Apply to theme a group of Buttons using a shared context.
This is useful for applying consistent sizing or variants to multiple buttons
without passing props to each one individually.
import { Button, ButtonDemo, YStack } from 'tamagui'
export default () => (
<YStack gap="$4">
<Button.Apply size="$2" variant="outlined">
<Button>Small Outlined 1</Button>
<Button>Small Outlined 2</Button>
<Button icon={Star}>With Icon</Button>
</Button.Apply>
<Button.Apply size="$5">
<Button>Large 1</Button>
<Button theme="blue">Large Themed</Button>
</Button.Apply>
</YStack>
)
Web Form Props
Button supports all standard HTML <button> attributes for form integration.
These props are web-only and ignored on native:
import { Button, Form } from 'tamagui'
export default () => (
<Form action="/submit">
<Button type="submit">Submit Form</Button>
<Button type="reset">Reset</Button>
<Button type="button">Regular Button (default)</Button>
{/* Override form attributes */}
<Button type="submit" formAction="/alternative-endpoint" formMethod="post">
Submit to Different Endpoint
</Button>
</Form>
)
Text Styling
Changed from v1: In v1, you could pass text style props like color,
fontSize, fontWeight, fontFamily, and letterSpacing directly to
<Button> and they would be forwarded to the button's text via context. In v2,
this is no longer supported — Button's frame is a View and text style props
passed to it are ignored.
To customize text appearance, use Button.Text explicitly:
import { Button } from 'tamagui'
export default () => (
<Button>
<Button.Text color="blue" fontSize="$5" fontWeight="bold">
Styled text
</Button.Text>
</Button>
)
Interactive Text Styles
Combine Button.Text with the group prop on Button to coordinate text
styles across hover, press, and focus states:
import { Button } from 'tamagui'
export default () => (
<Button group="btn" bg="pink">
<Button.Text color="blue" $group-btn-hover={{ color: 'red' }}>
Hello world
</Button.Text>
</Button>
)
The group prop lets any child reference interactive states like
$group-btn-hover, $group-btn-press, and $group-btn-focus for
precise styling per interaction state.
Creating Your Own Button
Tamagui now has all the features necessary to make creating a custom Button easy enough that you may want to roll your own button. Learn how to do it with our dedicated guide, How to Build a Button.
API Reference
Buttons extend Stack views inheriting all the Tamagui standard props, plus:
<PropsTable
data={[
{
name: 'size',
required: false,
type: 'SizeTokens | number',
description: Set a size from your theme's size tokens (e.g., "$4") or a specific number. Adjusts padding, font size, and icon sizes.,
},
{
name: 'variant',
required: false,
type: '"outlined" | undefined',
description: 'Applies the "outlined" button style.',
},
{
name: 'elevation',
required: false,
type: 'SizeTokens | number',
description: Adds a shadow/elevation effect to the button. Accepts a size token or number.,
},
{
name: 'disabled',
required: false,
type: 'boolean',
description:
'If true, the button will be non-interactive and visually disabled. Sets pointerEvents: "none".',
},
{
name: 'theme',
required: false,
type: 'string',
description: Apply a theme just to the button and its children.,
},
{
name: 'icon',
required: false,
type: 'React.ReactNode | React.ComponentType<{ color?: string, size?: number }>',
description: Pass any React element or a component. Appears before the text. If a component is passed, 'color' and 'size' props are passed to it.,
},
{
name: 'iconAfter',
required: false,
type: 'React.ReactNode | React.ComponentType<{ color?: string, size?: number }>',
description: Pass any React element or a component. Appears after the text. If a component is passed, 'color' and 'size' props are passed to it.,
},
{
name: 'iconSize',
required: false,
type: 'SizeTokens',
description: Explicitly set the size of the icon, overriding the default size derived from the Button's 'size' prop. Uses theme size tokens (e.g., "$2").,
},
{
name: 'scaleIcon',
required: false,
type: 'number',
description: Scale the icon by this factor. Default is 1. Applied after 'iconSize' or the default size calculation.,
},
{
name: 'circular',
required: false,
type: boolean,
description: Forces a circular button. Applies border radius to make the button a circle.,
},
{
name: 'chromeless',
required: false,
type: 'boolean | "all"',
description:
'Removes default Tamagui visual styles (background, border) for a more minimal appearance, while keeping layout and interactions. If "all", removes hover/press/focus styles too.',
},
{
name: 'unstyled',
required: false,
type: boolean,
description: Removes all Tamagui default styles, including layout, interactions, and accessibility attributes. Prefer 'chromeless' for removing only visual styles.,
},
// Web-only form props
{
name: '// Web Form Props',
description:
'The following props are web-only and provide full HTML button form semantics. They are ignored on native.',
type: '---',
},
{
name: 'type',
required: false,
type: '"button" | "submit" | "reset"',
description:
'Web-only. The button type. Defaults to "button" to prevent unintended form submissions.',
},
{
name: 'form',
required: false,
type: 'string',
description: 'Web-only. The ID of the form element the button is associated with.',
},
{
name: 'formAction',
required: false,
type: 'string',
description: "Web-only. URL for form submission, overrides the form's action.",
},
{
name: 'formMethod',
required: false,
type: '"get" | "post"',
description: 'Web-only. HTTP method for form submission.',
},
{
name: 'formEncType',
required: false,
type: 'string',
description: 'Web-only. Encoding type for form data.',
},
{
name: 'formNoValidate',
required: false,
type: 'boolean',
description: 'Web-only. Bypass form validation when submitting.',
},
{
name: 'formTarget',
required: false,
type: 'string',
description: 'Web-only. Where to display form response (_self, _blank, etc).',
},
{
name: 'name',
required: false,
type: 'string',
description: 'Web-only. Name submitted with form data.',
},
{
name: 'value',
required: false,
type: 'string',
description: 'Web-only. Value submitted with form data.',
},
{
name: 'popoverTarget',
required: false,
type: 'string',
description: 'Web-only. ID of popover element to control.',
},
{
name: 'popoverTargetAction',
required: false,
type: '"hide" | "show" | "toggle"',
description: 'Web-only. Action to perform on the popover.',
},
// Note about text styling
{
name: '// Text Styling',
description:
'Button does not support color directly. To style text color, use Button.Text with the group prop for interactive states. See the Text Styling section above.',
type: '---',
},
]}
/>
components/card/1.0.0
title: Card description: Sizable, themeable cards with a flexible API. name: card component: Card package: card demoName: Card
<Highlights
features={[
Sizable with a size prop that passes to Card children.,
Themeable helper props like elevate.,
Background component that handles positioning.,
]}
/>
Installation
Card is already installed in tamagui, or you can install it independently:
npm install @tamagui/card
Anatomy
import { Card } from 'tamagui' // or '@tamagui/card'
export default () => (
<Card>
<Card.Header />
<Card.Footer />
{/* any other components */}
<Card.Background />
</Card>
)
API Reference
Card
Frame of the card, extends ThemeableStack props, adding:
<PropsTable
data={[
{
name: 'size',
type: 'SizeTokens',
required: false,
description: Passes size down to all sub-components when set for padding, arrow, borderRadius.,
},
{
name: 'unstyled',
required: false,
type: boolean,
description: Removes all default Tamagui styles.,
},
]}
/>
Card.Header
Extends ThemeableStack, adding:
<PropsTable
data={[
{
name: 'unstyled',
required: false,
type: boolean,
description: Removes all default Tamagui styles.,
},
]}
/>
Card.Footer
Extends ThemeableStack, adding:
<PropsTable
data={[
{
name: 'unstyled',
required: false,
type: boolean,
description: Removes all default Tamagui styles.,
},
]}
/>
Card.Background
Extends YStack, set to fullscreen and zIndex below Header/Footer.
<PropsTable
data={[
{
name: 'unstyled',
required: false,
type: boolean,
description: Removes all default Tamagui styles.,
},
]}
/>
components/card/2.0.0
title: Card description: Sizable, themeable cards with a flexible API name: card component: Card package: card demoName: Card
<Highlights
features={[
Sizable with a size prop that passes to Card children.,
Themeable helper props like elevate.,
Background component that handles positioning.,
]}
/>
Installation
Card is already installed in tamagui, or you can install it independently:
npm install @tamagui/card
Anatomy
import { Card } from 'tamagui' // or '@tamagui/card'
export default () => (
<Card>
<Card.Header />
<Card.Footer />
{/* any other components */}
<Card.Background />
</Card>
)
API Reference
Card
Frame of the card, extends ThemeableStack props, adding:
<PropsTable
data={[
{
name: 'size',
type: 'SizeTokens',
required: false,
description: Passes size down to all sub-components when set for padding, arrow, borderRadius.,
},
{
name: 'unstyled',
required: false,
type: boolean,
description: Removes all default Tamagui styles.,
},
]}
/>
Card.Header
Extends ThemeableStack, adding:
<PropsTable
data={[
{
name: 'unstyled',
required: false,
type: boolean,
description: Removes all default Tamagui styles.,
},
]}
/>
Card.Footer
Extends ThemeableStack, adding:
<PropsTable
data={[
{
name: 'unstyled',
required: false,
type: boolean,
description: Removes all default Tamagui styles.,
},
]}
/>
Card.Background
Extends YStack, set to fullscreen and zIndex below Header/Footer.
<PropsTable
data={[
{
name: 'unstyled',
required: false,
type: boolean,
description: Removes all default Tamagui styles.,
},
]}
/>
components/checkbox/1.3.0
title: Checkbox description: A simple checkbox component name: checkbox component: Checkbox package: checkbox demoName: Checkbox
Checkbox
Use in forms to toggle between two states.
<Highlights
features={[
Supports indeterminate state.,
Accessible, easy to compose and customize.,
Sizable & works controlled or uncontrolled.,
Ability to opt-out to native checkbox on web.,
]}
/>
Installation
Checkbox is already installed in tamagui, or you can install it independently:
npm install @tamagui/checkbox
Usage
import { Check } from '@tamagui/lucide-icons-2'
import { Checkbox } from 'tamagui'
export default () => (
<Checkbox size="$4">
<Checkbox.Indicator>
<Check />
</Checkbox.Indicator>
</Checkbox>
)
API Reference
Checkbox
Checkbox extend ThemeableStack inheriting all the props, plus:
<PropsTable
data={[
{
name: 'labeledBy',
type: 'string',
description: Set aria-labeled-by.,
},
{
name: 'name',
type: 'string',
description: Equivalent to input name.,
},
{
name: 'value',
type: 'string',
description: Give it a value (for use in HTML forms).,
},
{
name: 'checked',
type: 'boolean',
description: Control the input.,
},
{
name: 'defaultChecked',
type: 'boolean',
description: Uncontrolled default value.,
},
{
name: 'required',
type: 'boolean',
description: Sets aria-required.,
},
{
name: 'native',
type: 'boolean',
description: Renders native checkbox input on web.,
default: false,
},
{
name: 'onCheckedChange',
type: '(checked: boolean | "indeterminate") => void',
description: 'Callback that fires when the checkbox state is changed.',
},
{
name: 'sizeAdjust',
type: 'number',
description: Adjust the checkbox size scaling by this number.,
},
{
name: 'scaleIcon',
type: 'number',
description: Scale the indicator icon more than usual by this number.,
},
{
name: 'scaleSize',
type: 'number',
default: '0.5',
description: The Tamagui size tokens should map to the height of a button at any given step. This means you want somewhat smaller checkboxes typically.,
},
{
name: 'unstyled',
required: false,
type: boolean,
description: Removes all default Tamagui styles.,
},
]}
/>
Checkbox.Indicator
Checkbox.Indicator extend ThemeableStack inheriting all the props, plus:
<PropsTable
data={[
{
name: 'forceMount',
required: false,
type: boolean,
description: Used to force mounting when more control is needed.,
},
{
name: 'disablePassStyles',
required: false,
type: 'boolean',
description: Used to disable passing styles down to children.,
},
]}
/>
components/checkbox/1.85.0
title: Checkbox description: A simple checkbox component name: checkbox component: Checkbox package: checkbox demoName: Checkbox
Checkbox
Toggle state in forms.
<Tabs.Content value="styled">
</Tabs.Content> <Tabs.Content value="unstyled">
</Tabs.Content> <Tabs.Content value="headless">
</Tabs.Content>
<Highlights
features={[
Supports indeterminate state.,
Accessible, easy to compose and customize.,
Sizable & works controlled or uncontrolled.,
Ability to opt-out to native checkbox on web.,
]}
/>
Installation
<Tabs.Content value="styled">
Checkbox is already installed in tamagui, or you can install it independently:
npm install @tamagui/checkbox
</Tabs.Content>
<Tabs.Content value="unstyled">
Checkbox is already installed in tamagui, or you can install it independently:
npm install @tamagui/checkbox
</Tabs.Content>
<Tabs.Content value="headless">
To use the headless switch, you want to import it from the
@tamagui/switch-headless package. This package has no dependency on
@tamagui/core, but still works off the react-native APIs.
This means can bring your own style library.
npm install @tamagui/switch-headless
</Tabs.Content>
Usage
<Tabs.Content value="styled">
import { Check } from '@tamagui/lucide-icons-2'
import { Checkbox } from 'tamagui'
export default () => (
<Checkbox size="$4">
<Checkbox.Indicator>
<Check />
</Checkbox.Indicator>
</Checkbox>
)
</Tabs.Content>
<Tabs.Content value="unstyled">
Use the createCheckbox export to create a fully custom checkbox that still
uses the Tamagui styling system. This is similar to setting unstyled, but goes
a bit further. It doesn't add any types for size or unstyled, and it won't
automatically apply the active theme. If does pass the checked prop down as
indicated in the types of createCheckbox.
</Tabs.Content>
<Tabs.Content value="headless">
Using the useCheckbox API, you can make your own Checkbox from scratch.
</Tabs.Content>
API Reference
Checkbox
Checkbox extend ThemeableStack inheriting all the
props, plus:
<PropsTable
data={[
{
name: 'labeledBy',
type: 'string',
description: Set aria-labeled-by.,
},
{
name: 'name',
type: 'string',
description: Equivalent to input name.,
},
{
name: 'value',
type: 'string',
description: Give it a value (for use in HTML forms).,
},
{
name: 'checked',
type: 'boolean',
description: Control the input.,
},
{
name: 'defaultChecked',
type: 'boolean',
description: Uncontrolled default value.,
},
{
name: 'required',
type: 'boolean',
description: Sets aria-required.,
},
{
name: 'native',
type: 'boolean',
description: Renders native checkbox input on web.,
default: false,
},
{
name: 'onCheckedChange',
type: '(checked: boolean | "indeterminate") => void',
description: 'Callback that fires when the checkbox state is changed.',
},
{
name: 'sizeAdjust',
type: 'number',
description: Adjust the checkbox size scaling by this number.,
},
{
name: 'scaleIcon',
type: 'number',
description: Scale the indicator icon more than usual by this number.,
},
{
name: 'scaleSize',
type: 'number',
default: '0.5',
description: The Tamagui size tokens should map to the height of a button at any given step. This means you want somewhat smaller checkboxes typically.,
},
{
name: 'unstyled',
required: false,
type: boolean,
description: Removes all default Tamagui styles.,
},
]}
/>
Checkbox.Indicator
Checkbox.Indicator extend ThemeableStack inheriting all the
props, plus:
<PropsTable
data={[
{
name: 'forceMount',
required: false,
type: boolean,
description: Used to force mounting when more control is needed.,
},
{
name: 'disablePassStyles',
required: false,
type: 'boolean',
description: Used to disable passing styles down to children.,
},
]}
/>
components/checkbox/1.89.0
title: Checkbox description: Toggle state in forms. name: checkbox component: Checkbox package: checkbox demoName: Checkbox
<Tabs.Content value="styled">
</Tabs.Content> <Tabs.Content value="unstyled">
</Tabs.Content> <Tabs.Content value="headless">
</Tabs.Content>
<Highlights
features={[
Supports indeterminate state.,
Accessible, easy to compose and customize.,
Sizable & works controlled or uncontrolled.,
Ability to opt-out to native checkbox on web.,
]}
/>
Installation
<Tabs.Content value="styled">
Checkbox is already installed in tamagui, or you can install it independently:
npm install @tamagui/checkbox
</Tabs.Content>
<Tabs.Content value="unstyled">
Checkbox is already installed in tamagui, or you can install it independently:
npm install @tamagui/checkbox
</Tabs.Content>
<Tabs.Content value="headless">
To use the headless checkbox, you want to import it from the
@tamagui/checkbox-headless package. This package has no dependency on
@tamagui/core, but still works off the react-native APIs.
This means you can bring your own style library.
npm install @tamagui/checkbox-headless
</Tabs.Content>
Usage
<Tabs.Content value="styled">
import { Check } from '@tamagui/lucide-icons-2'
import { Checkbox } from 'tamagui'
export default () => (
<Checkbox size="$4">
<Checkbox.Indicator>
<Check />
</Checkbox.Indicator>
</Checkbox>
)
</Tabs.Content>
<Tabs.Content value="unstyled">
Use the createCheckbox export to create a fully custom checkbox that still
uses the Tamagui styling system. This is similar to setting unstyled, but goes
a bit further. It doesn't add any types for size or unstyled, and it won't
automatically apply the active theme. It does pass the checked prop down as
indicated in the types of createCheckbox.
</Tabs.Content>
<Tabs.Content value="headless">
Using the useCheckbox API, you can make your own Checkbox from scratch.
</Tabs.Content>
API Reference
Checkbox
Checkbox extend ThemeableStack inheriting all the
props, plus:
<PropsTable
data={[
{
name: 'labeledBy',
type: 'string',
description: Set aria-labeled-by.,
},
{
name: 'name',
type: 'string',
description: Equivalent to input name.,
},
{
name: 'value',
type: 'string',
description: Give it a value (for use in HTML forms).,
},
{
name: 'checked',
type: 'boolean',
description: Control the input.,
},
{
name: 'defaultChecked',
type: 'boolean',
description: Uncontrolled default value.,
},
{
name: 'required',
type: 'boolean',
description: Sets aria-required.,
},
{
name: 'native',
type: 'boolean',
description: Renders native checkbox input on web.,
default: false,
},
{
name: 'onCheckedChange',
type: '(checked: boolean | "indeterminate") => void',
description: 'Callback that fires when the checkbox state is changed.',
},
{
name: 'sizeAdjust',
type: 'number',
description: Adjust the checkbox size scaling by this number.,
},
{
name: 'scaleIcon',
type: 'number',
description: Scale the indicator icon more than usual by this number.,
},
{
name: 'scaleSize',
type: 'number',
default: '0.5',
description: The Tamagui size tokens should map to the height of a button at any given step. This means you want somewhat smaller checkboxes typically.,
},
{
name: 'unstyled',
required: false,
type: boolean,
description: Removes all default Tamagui styles.,
},
]}
/>
Checkbox.Indicator
Checkbox.Indicator extend ThemeableStack inheriting all the
props, plus:
<PropsTable
data={[
{
name: 'forceMount',
required: false,
type: boolean,
description: Used to force mounting when more control is needed.,
},
{
name: 'disablePassStyles',
required: false,
type: 'boolean',
description: Used to disable passing styles down to children.,
},
]}
/>
components/checkbox/2.0.0
title: Checkbox description: Toggle state in forms name: checkbox component: Checkbox package: checkbox demoName: Checkbox
<Tabs.Content value="styled">
</Tabs.Content> <Tabs.Content value="unstyled">
</Tabs.Content> <Tabs.Content value="headless">
</Tabs.Content>
<Highlights
features={[
Supports indeterminate state.,
Accessible, easy to compose and customize.,
Sizable & works controlled or uncontrolled.,
Ability to opt-out to native checkbox on web.,
]}
/>
Installation
<Tabs.Content value="styled">
Checkbox is already installed in tamagui, or you can install it independently:
npm install @tamagui/checkbox
</Tabs.Content>
<Tabs.Content value="unstyled">
Checkbox is already installed in tamagui, or you can install it independently:
npm install @tamagui/checkbox
</Tabs.Content>
<Tabs.Content value="headless">
To use the headless checkbox, you want to import it from the
@tamagui/checkbox-headless package. This package has no dependency on
@tamagui/core, but still works off the react-native APIs.
This means you can bring your own style library.
npm install @tamagui/checkbox-headless
</Tabs.Content>
Usage
<Tabs.Content value="styled">
import { Check } from '@tamagui/lucide-icons-2'
import { Checkbox } from 'tamagui'
export default () => (
<Checkbox size="$4">
<Checkbox.Indicator>
<Check />
</Checkbox.Indicator>
</Checkbox>
)
</Tabs.Content>
<Tabs.Content value="unstyled">
Use the createCheckbox export to create a fully custom checkbox that still
uses the Tamagui styling system. This is similar to setting unstyled, but goes
a bit further. It doesn't add any types for size or unstyled, and it won't
automatically apply the active theme. It does pass the checked prop down as
indicated in the types of createCheckbox.
</Tabs.Content>
<Tabs.Content value="headless">
The useCheckbox hook provides all the state and accessibility props needed to build a custom checkbox with any styling solution.
Basic Usage
import { useCheckbox } from '@tamagui/checkbox-headless'
import { useState } from 'react'
import { Pressable, View } from 'react-native'
function MyCheckbox({ defaultChecked, onCheckedChange, ...props }) {
const [checked, setChecked] = useState(defaultChecked || false)
const { checkboxProps, checkboxRef, bubbleInput } = useCheckbox(
props,
[checked, setChecked],
null
)
return (
<>
<Pressable
ref={checkboxRef}
{...checkboxProps}
style={{
width: 24,
height: 24,
borderRadius: 4,
borderWidth: 2,
borderColor: checked ? '#3b82f6' : '#d1d5db',
backgroundColor: checked ? '#3b82f6' : 'transparent',
justifyContent: 'center',
alignItems: 'center',
}}
>
{checked && <View style={{ width: 12, height: 12, backgroundColor: 'white' }} />}
</Pressable>
{bubbleInput}
</>
)
}
</Tabs.Content>
API Reference
Checkbox
Checkbox extends ThemeableStack inheriting all the
props, plus:
<PropsTable
data={[
{
name: 'labeledBy',
type: 'string',
description: Set aria-labeled-by.,
},
{
name: 'name',
type: 'string',
description: Equivalent to input name.,
},
{
name: 'value',
type: 'string',
description: Give it a value (for use in HTML forms).,
},
{
name: 'checked',
type: 'boolean',
description: Control the input.,
},
{
name: 'defaultChecked',
type: 'boolean',
description: Uncontrolled default value.,
},
{
name: 'required',
type: 'boolean',
description: Sets aria-required.,
},
{
name: 'native',
type: 'boolean',
description: Renders native checkbox input on web.,
default: false,
},
{
name: 'onCheckedChange',
type: '(checked: boolean | "indeterminate") => void',
description: 'Callback that fires when the checkbox state is changed.',
},
{
name: 'sizeAdjust',
type: 'number',
description: Adjust the checkbox size scaling by this number.,
},
{
name: 'scaleIcon',
type: 'number',
description: Scale the indicator icon more than usual by this number.,
},
{
name: 'scaleSize',
type: 'number',
default: '0.5',
description: The Tamagui size tokens should map to the height of a button at any given step. This means you want somewhat smaller checkboxes typically.,
},
{
name: 'unstyled',
required: false,
type: boolean,
description: Removes all default Tamagui styles.,
},
{
name: 'activeStyle',
required: false,
type: StyleProp,
description: Styles to apply when the checkbox is checked.,
},
{
name: 'activeTheme',
required: false,
type: string | null,
description: Theme to apply when the checkbox is checked. Set to null for no theme change.,
},
]}
/>
Checkbox.Indicator
Checkbox.Indicator extends ThemeableStack inheriting all the
props, plus:
<PropsTable
data={[
{
name: 'forceMount',
required: false,
type: boolean,
description: Used to force mounting when more control is needed.,
},
{
name: 'disablePassStyles',
required: false,
type: 'boolean',
description: Used to disable passing styles down to children.,
},
]}
/>
<Tabs.Content value="headless">
useCheckbox
The useCheckbox hook accepts three arguments:
const { checkboxProps, checkboxRef, bubbleInput } = useCheckbox(
props, // CheckboxProps
state, // [checked: CheckedState, setChecked: (checked: CheckedState) => void]
ref // React.Ref
)
CheckedState
The checkbox supports three states:
true- checkedfalse- unchecked'indeterminate'- indeterminate/mixed state (useful for "select all" patterns)
Props (first argument)
<PropsTable
data={[
{
name: 'labelledBy',
type: 'string',
description: Set aria-labelledby for accessibility.,
},
{
name: 'disabled',
type: 'boolean',
description: Whether the checkbox is disabled.,
},
{
name: 'name',
type: 'string',
description: Form input name for the hidden input.,
},
{
name: 'value',
type: 'string',
default: '"on"',
description: Form input value.,
},
{
name: 'required',
type: 'boolean',
description: Whether the checkbox is required in a form.,
},
{
name: 'onCheckedChange',
type: '(checked: CheckedState) => void',
description: Called when checked state changes.,
},
{
name: 'onPress',
type: '(event) => void',
description: Called when checkbox is pressed (composed with internal handler).,
},
]}
/>
State (second argument)
A tuple of [checked, setChecked] where:
checked: Current state (boolean | 'indeterminate')setChecked: React state setter function
Return Value
| Property | Type | Description |
|---|---|---|
checkboxProps | object | Props to spread on your checkbox element (role, aria-checked, onPress, etc.) |
checkboxRef | Ref | Composed ref to attach to your checkbox element |
bubbleInput | ReactNode | null | Hidden input for form compatibility (render as sibling, web only) |
</Tabs.Content>
components/context-menu/2.0.0
title: Context Menu description: A menu component triggered by right-click on web and long press on touch devices name: context-menu component: ContextMenu package: context-menu demoName: ContextMenu
<Highlights features={[ 'Full keyboard navigation.', 'Supports items, icons, images, checkboxes, groups, and more.', 'Supports submenus.', 'Supports modal and non-modal modes.', 'Supports native menus on native platforms.', 'Customizable alignment, offsets, and positioning.', 'Support for native iOS and Android icons.', 'Supports previews on iOS.', ]} />
ContextMenu displays a menu triggered by right-click on web or long-press on mobile. It supports submenus, native platform menus with iOS previews, and automatically stacks above other content.
Installation
ContextMenu is already installed in tamagui, or you can install it independently:
yarn add @tamagui/context-menu
If you want to use native menus, add these dependencies:
yarn add @react-native-menu/menu
yarn add react-native-ios-context-menu
yarn add react-native-ios-utilities
yarn add zeego
yarn add sf-symbols-typescript
Then add the setup import at your app entry point:
import '@tamagui/native/setup-zeego'
Anatomy
Import all parts and piece them together.
import { ContextMenu } from 'tamagui' // or '@tamagui/context-menu'
export default () => (
<ContextMenu>
<ContextMenu.Trigger asChild>
<YStack>
<Text>Right Click or longPress</Text>
</YStack>
</ContextMenu.Trigger>
<ContextMenu.Portal zIndex={100}>
<ContextMenu.Content>
<ContextMenu.Item>
<ContextMenu.ItemTitle>About Notes</ContextMenu.ItemTitle>
</ContextMenu.Item>
<ContextMenu.Item>
<ContextMenu.ItemTitle>Settings</ContextMenu.ItemTitle>
</ContextMenu.Item>
{/* when title is nested inside a React element then you need to use `textValue` */}
<ContextMenu.Item textValue="Calendar">
<ContextMenu.ItemTitle>
<Text>Calendar</Text>
</ContextMenu.ItemTitle>
<ContextMenu.ItemIcon>
<Calendar color="gray" size="$1" />
</ContextMenu.ItemIcon>
</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Sub>
<ContextMenu.SubTrigger>
<ContextMenu.ItemTitle>Actions</ContextMenu.ItemTitle>
</ContextMenu.SubTrigger>
<ContextMenu.Portal zIndex={200}>
<ContextMenu.SubContent>
<ContextMenu.Label fontSize={'$1'}>Note settings</ContextMenu.Label>
<ContextMenu.Item onSelect={onSelect} key="create-note">
<ContextMenu.ItemTitle>Create note</ContextMenu.ItemTitle>
</ContextMenu.Item>
<ContextMenu.Item onSelect={onSelect} key="delete-all">
<ContextMenu.ItemTitle>Delete all notes</ContextMenu.ItemTitle>
</ContextMenu.Item>
<ContextMenu.Item onSelect={onSelect} key="sync-all">
<ContextMenu.ItemTitle>Sync notes</ContextMenu.ItemTitle>
</ContextMenu.Item>
</ContextMenu.SubContent>
</ContextMenu.Portal>
</ContextMenu.Sub>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu>
)
API Reference
ContextMenu
Contains every component for the ContextMenu.
<PropsTable
data={[
{
name: 'children',
type: 'React.ReactNode',
required: true,
description: 'Menu parts: Trigger, Portal, Content, Items, etc.',
},
{
name: 'placement',
type: 'Placement',
required: false,
description: Where the menu appears relative to the trigger. Options: 'top' | 'right' | 'bottom' | 'left' with optional '-start' | '-end' alignment.,
},
{
name: 'open',
type: 'boolean',
required: false,
description: 'Controlled open state for the menu.',
},
{
name: 'defaultOpen',
type: 'boolean',
required: false,
description: 'Initial open state when uncontrolled.',
},
{
name: 'onOpenChange',
type: '(open: boolean, event?: { preventDefault: () => void }) => void',
required: false,
description: 'Called when the menu opens or closes. Call event.preventDefault() to cancel and allow the native context menu to show instead.',
},
{
name: 'onOpenWillChange',
type: '(open: boolean) => void',
required: false,
platform: 'ios',
description: 'Called before the open/close animation begins.',
},
{
name: 'modal',
type: 'boolean',
default: 'true',
required: false,
description:
'When true, traps focus inside the menu and blocks outside scroll/interactions.',
},
{
name: 'stayInFrame',
type: 'ShiftProps | boolean',
required: false,
default: '{ padding: 10 }',
description: 'Shifts the menu horizontally to stay within viewport bounds. Pass an object to customize shift behavior (mainAxis, crossAxis, padding).',
},
{
name: 'allowFlip',
type: 'FlipProps | boolean',
required: false,
description: 'Flips the menu to the opposite side if there is insufficient space.',
},
{
name: 'offset',
type: 'OffsetOptions',
required: false,
description: 'Distance between the menu and its trigger.',
},
{
name: 'unstyled',
required: false,
type: 'boolean',
description: 'Removes all default Tamagui styles.',
},
]}
/>
Allowing Native Context Menu
You can call event.preventDefault() in onOpenChange to prevent the Tamagui menu from opening and allow the native browser context menu to appear instead:
<ContextMenu
onOpenChange={(open, event) => {
if (someCondition) {
// prevent Tamagui menu, let native context menu show
event?.preventDefault()
}
}}
>
{/* ... */}
</ContextMenu>
ContextMenu.Portal
This is necessary for the ContextMenu.
<PropsTable data={[ { name: 'zIndex', required: false, type: 'number', description: 'Stacking order of the portal layer.', }, { name: 'children', type: 'React.ReactNode', required: true, description: 'Content to render inside the portal.', }, { name: 'forceMount', type: 'true', required: false, description: 'Forces the portal to stay mounted, useful for controlling animations.', }, ]} />
ContextMenu.Trigger
The ContextMenu will only be triggered when the user right-clicks or long-presses within the Trigger area.
<PropsTable data={[ { name: 'action', required: false, type: 'press|longPress', default: 'longPress', platform: 'android/ios', description: "Works with the native prop and accepts 'press' or 'longPress'. The default is 'longPress' for ContextMenu.", }, ]} />
ContextMenu.Content
Contains the content of the ContextMenu.
<PropsTable data={[ { name: 'children', type: 'React.ReactNode', required: true, description: 'Menu items, groups, labels, separators, and submenus.', }, { name: 'loop', type: 'boolean', required: false, default: 'false', description: 'Whether keyboard navigation wraps from last to first item.', }, { name: 'forceMount', type: 'true', required: false, description: 'Forces the content to stay mounted, useful for controlling animations.', }, { name: 'onCloseAutoFocus', type: '(event: Event) => void', required: false, description: 'Called when focus returns to the trigger after closing.', }, { name: 'onEscapeKeyDown', type: '(event: KeyboardEvent) => void', required: false, description: 'Called when the escape key is pressed. Can be prevented.', }, { name: 'onPointerDownOutside', type: '(event: PointerEvent) => void', required: false, description: 'Called when a pointer event occurs outside the content.', }, { name: 'onInteractOutside', type: '(event: Event) => void', required: false, description: 'Called when any interaction occurs outside the content.', }, ]} />
ContextMenu.Item
A selectable menu item that triggers an action when selected.
<PropsTable data={[ { name: 'key', type: 'string', required: true, description: 'Unique identifier for the item.', }, { name: 'disabled', type: 'boolean', required: false, default: 'false', description: 'Prevents interaction and dims the item.', }, { name: 'destructive', type: 'boolean', required: false, platform: 'ios/android', description: 'Renders the item in red on iOS to indicate a dangerous action (e.g. delete). No effect on web.', }, { name: 'hidden', type: 'boolean', required: false, description: 'Hides the item from the menu.', }, { name: 'onSelect', type: '(event?: Event) => void', required: false, description: 'Called when the item is selected via click or keyboard.', }, { name: 'onFocus', type: '() => void', required: false, description: 'Called when the item receives focus.', }, { name: 'onBlur', type: '() => void', required: false, description: 'Called when the item loses focus.', }, { name: 'textValue', type: 'string', required: false, platform: 'ios/android', description: 'Text used for typeahead and native menus. Required when ItemTitle contains a React node instead of a string.', }, ]} />
ContextMenu.ItemTitle
Renders the title of the menu item.
<PropsTable
data={[
{
name: 'children',
type: 'string | React.ReactNode',
required: true,
description: 'The title text or element to display.',
},
]}
/>
You can directly pass a text node to the ItemTitle. However, if you use a nested
React node like <Text>, you need to pass textValue to the <Item> so that it
works with native menus.
ContextMenu.ItemIcon
A component to render an icon. For non-native menus, you can pass an icon
component. For native menus, you can pass platform-specific icons to the
android/ios props.
On iOS, it renders the native SF Symbols icons.
<PropsTable data={[ { name: 'children', type: 'React.ReactNode', required: false, description: 'Fallback icon for web when native icons are not available.', }, { name: 'ios', type: 'object', required: false, platform: 'ios', description: 'SF Symbol configuration: name, weight, scale, hierarchicalColor, paletteColors.', }, { name: 'android', type: 'object', required: false, platform: 'android', description: 'Android resource drawable name.', }, ]} />
<ContextMenu.ItemIcon
ios={{
name: '0.circle.fill', // required
pointSize: 5,
weight: 'semibold',
scale: 'medium',
// can also be a color string. Requires iOS 15+
hierarchicalColor: {
dark: 'blue',
light: 'green',
},
// alternative to hierarchical color. Requires iOS 15+
paletteColors: [
{
dark: 'blue',
light: 'green',
},
],
}}
>
<CircleIcon />
</ContextMenu.ItemIcon>
ContextMenu.ItemImage
A component to render an item image. For native menus, it only works on iOS. It
takes the same properties as @tamagui/image.
ContextMenu.ItemSubtitle
A component to render a subtitle for the menu item. For native menus, it only works on iOS.
<PropsTable data={[ { name: 'children', type: 'string', required: true, description: 'The subtitle text to display below the title.', }, ]} />
ContextMenu.Group
A component that groups multiple menu items together.
<PropsTable data={[ { name: 'children', type: 'React.ReactNode', required: true, description: 'Menu items to group together.', }, ]} />
ContextMenu.CheckboxItem
A menu item with a checkbox that can be toggled on/off.
<PropsTable data={[ { name: 'key', type: 'string', required: true, description: 'Unique identifier for the checkbox item.', }, { name: 'disabled', type: 'boolean', required: false, default: 'false', desc
… [truncated — open the raw llms.txt above for the full file]
Meet the modern standard for public facing documentation. Beautiful out of the box, easy to maintain, and optimized for user engagement.
Search through billions of items for similar matches to any object, in milliseconds. It’s the next generation of search, an API call away.
Build and deploy reliable background jobs with no timeouts and no infrastructure to manage.
Get the simple developer experience of SQLite in production, and scale your multi-tenant backend with unlimited databases.
Upstash is a serverless data platform providing low latency and high scalability for real-time applications.
One-click deployments built for teams, tuned for Laravel, loaded with tools and goodies you're going to love.