# 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
---
```tsx hero template=Accordion
```
## Installation
Accordion is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/accordion
```
## Anatomy
Import all parts and piece them together.
```jsx
import { Accordion } from 'tamagui' // or '@tamagui/accordion'
export default () => (
)
```
## API Reference
### Accordion
Contains all the parts of an accordion.
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.
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.
### Trigger
Toggles the collapsed state of its associated item. It should be nested inside of an `Accordion.Header`.
### Content
Contains the collapsible content for an item.
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.
```jsx line=1
……
```
### Allow collapsing all items
Use the `collapsible` prop to allow all items to close.
```jsx line=1
……
```
### Multiple items open at the same time
Set the `type` prop to `multiple` to enable opening multiple items at once.
```jsx line=1
……
```
## Accessibility
Adheres to the [Accordion WAI-ARIA design pattern](https://www.w3.org/TR/wai-aria-practices-1.1/#accordion).
## 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
---
```tsx hero template=Accordion
```
## Installation
Accordion is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/accordion
```
## Anatomy
Import all parts and piece them together.
```jsx
import { Accordion } from 'tamagui' // or '@tamagui/accordion'
export default () => (
)
```
## API Reference
### Accordion
Contains all the parts of an accordion.
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.
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.
### Accordion.Trigger
Toggles the collapsed state of its associated item. It should be nested inside of an `Accordion.Header`.
### Accordion.Content
Contains the collapsible content for an item.
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.
```jsx line=1
……
```
### Allow collapsing all items
Use the `collapsible` prop to allow all items to close.
```jsx line=1
……
```
### Multiple items open at the same time
Set the `type` prop to `multiple` to enable opening multiple items at once.
```jsx line=1
……
```
## Accessibility
Adheres to the [Accordion WAI-ARIA design pattern](https://www.w3.org/TR/wai-aria-practices-1.1/#accordion).
## 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
---
```tsx hero template=AlertDialog
```
## Installation
Alert Dialog is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/alert-dialog
```
In order to use this component independently of `tamagui`, you'll first need to install the `@tamagui/portal` package:
```bash
npm install @tamagui/portal
```
Then add `PortalProvider` to the root of your app:
```tsx fileName="App.tsx"
import { PortalProvider } from '@tamagui/portal'
import YourApp from './components/YourApp'
function App() {
return (
)
}
export default App
```
## Anatomy
```tsx
import { AlertDialog } from 'tamagui' // or '@tamagui/alert-dialog'
export default () => (
{/* ... */}
)
```
## API Reference
### AlertDialog
Contains every component for the AlertDialog. Shares all [Dialog Props](/docs/components/dialog#api), except modal which is on by default. Adds:
### AlertDialog.Trigger
Just [Tamagui Props](/docs/intro/props).
### AlertDialog.Portal
Renders AlertDialog into appropriate container. Beyond [Tamagui Props](/docs/intro/props), adds:
### AlertDialog.Content
Main container for AlertDialog content, this is where you should apply animations.
Beyond [Tamagui Props](/docs/intro/props), adds:
### AlertDialog.Overlay
Displays behind Content. Beyond [Tamagui Props](/docs/intro/props), adds:
### AlertDialog.Title
Required. Can wrap in VisuallyHidden to hide.
Defaults to H2, see [Headings](/docs/components/headings).
### AlertDialog.Description
Required. Can wrap in VisuallyHidden to hide.
Defaults to Paragraph, see [Paragraph](/docs/components/text).
### AlertDialog.Cancel
Closes the AlertDialog, accepts all YStack props. Recommended to use with your own component and `asChild`.
### PortalProvider
## 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:
```tsx
import { PortalProvider } from 'tamagui'
// this component used in react-navigation/expo-router with `presentation: "modal"`
export function Page() {
return (
{/* rest of your page, including the Dialog... */}
)
}
```
## 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
---
```tsx hero template=AlertDialog
```
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](/ui/z-index) above other content.
## Installation
Alert Dialog is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/alert-dialog
```
## Anatomy
```tsx
import { AlertDialog } from 'tamagui' // or '@tamagui/alert-dialog'
export default () => (
{/* ... */}
)
```
## API Reference
### AlertDialog
Contains every component for the AlertDialog. Shares all [Dialog Props](/docs/components/dialog#api), except modal which is on by default. Adds:
### AlertDialog.Trigger
Just [Tamagui Props](/docs/intro/props).
### AlertDialog.Portal
Renders AlertDialog into appropriate container. Beyond [Tamagui Props](/docs/intro/props), adds:
### AlertDialog.Content
Main container for AlertDialog content, this is where you should apply animations.
Beyond [Tamagui Props](/docs/intro/props), adds:
### AlertDialog.Overlay
Displays behind Content. Beyond [Tamagui Props](/docs/intro/props), adds:
### AlertDialog.Title
Required. Can wrap in VisuallyHidden to hide.
Defaults to H2, see [Headings](/docs/components/headings).
### AlertDialog.Description
Required. Can wrap in VisuallyHidden to hide.
Defaults to Paragraph, see [Paragraph](/docs/components/text).
### AlertDialog.Cancel
Closes the AlertDialog, accepts all YStack props. Recommended to use with your own component and `asChild`.
### AlertDialog.Action
Confirms the AlertDialog action, accepts all YStack props. Recommended to use with your own component and `asChild`.
### 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.
```tsx
Delete Account?This action cannot be undone.
```
### PortalProvider
## components/anchor/1.0.0
---
title: Anchor
description: Link to external websites.
name: html
component: Anchor
---
## Usage
The Anchor component provides a way to link to external websites. It extends [SizableText](/docs/components/text#sizable-text), 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](/docs/intro/props) as well as:
## components/anchor/2.0.0
---
title: Anchor
description: Link to external websites
name: anchor
component: Anchor
package: html
---
## Installation
Anchor is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/html
```
## Usage
The Anchor component provides a way to link to external websites. It extends [SizableText](/docs/components/text#sizable-text), 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](/docs/intro/props) as well as:
## 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
---
```tsx hero template=Avatar
```
## Installation
Avatar is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/avatar
```
## Usage
```tsx
import { Avatar } from 'tamagui'
export default () => (
)
```
## API Reference
### Avatar
Avatar extends [Square](/docs/components/shapes#shape-props), giving it all the [Tamagui standard props](/docs/intro/props) as well as `size` and `circular`.
### Avatar.Fallback
Avatar.Fallback extends [YStack](/docs/components/stacks), plus:
### Avatar.Image
Avatar.Image extends [Image](/docs/components/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
---
```tsx hero template=Avatar
```
## Installation
Avatar is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/avatar
```
## Usage
```tsx
import { Avatar } from 'tamagui'
export default () => (
)
```
## API Reference
### Avatar
Avatar extends [Square](/docs/components/shapes#shape-props), giving it all the [Tamagui standard props](/docs/intro/props) as well as `size` and `circular`.
### Avatar.Fallback
Avatar.Fallback extends [YStack](/docs/components/stacks), plus:
### Avatar.Image
Avatar.Image extends [Image](/docs/components/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.
```tsx hero template=Button
```
### Usage
```tsx
import { Button } from 'tamagui'
export default () =>
```
### 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.
```tsx
import { Button } from 'tamagui'
export default () =>
```
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](/docs/intro/props), adding:
## 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.
```tsx hero template=Button
```
### Usage
```tsx
import { Button } from 'tamagui'
export default () =>
```
### 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.
```tsx
import { Button } from 'tamagui'
export default () =>
```
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](/docs/intro/props), plus:
## 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.
```tsx hero template=Button
```
### Usage
```tsx
import { Button } from 'tamagui'
export default () =>
```
### 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.
```tsx
import { Button } from 'tamagui'
export default () =>
```
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](https://github.com/tamagui/tamagui/blob/v2/code/ui/button/src/Button.tsx) 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.
```tsx
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
type CustomButtonTextProps = GetProps
export type CustomButtonProps = TamaguiButtonProps &
CustomButtonFrameProps &
CustomButtonTextProps
export const Button = CustomButtonFrame.styleable((propsIn, ref) => {
const { props } = useButton(propsIn, { Text: CustomButtonText })
return
})
```
### Button props
Buttons extend Stack views inheriting all the [Tamagui standard props](/docs/intro/props), plus:
## components/button/1.28.0
---
title: Button
description: An incredibly flexible button.
name: button
component: Button
package: button
demoName: Button
---
```tsx hero template=Button
```
## Usage
When using the simple Button API, it's as simple as this:
```tsx
import { Button } from 'tamagui'
export default () =>
```
### 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.
```tsx
import { Button } from 'tamagui'
export default () =>
```
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](https://github.com/tamagui/tamagui/blob/main/code/ui/button/src/Button.tsx) 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](/docs/guides/how-to-build-a-button).
The previous `useButton` API is deprecated and will be removed in a future version. It's
brittle and is easily replaced with the new compound component APIs as described in the
guide.
## API Reference
### Button
Buttons extend Stack views inheriting all the [Tamagui standard props](/docs/intro/props), plus:
## components/button/2.0.0
---
title: Button
description: A simple button component
name: button
component: Button
package: button
demoName: Button
---
```tsx hero template=Button
```
## Installation
Button is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/button
```
## Usage
```tsx
import { Button } from 'tamagui'
export default () =>
```
## 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.
```tsx
import { Button } from 'tamagui'
export default () =>
```
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"`.
```tsx
import { Button, XStack } from 'tamagui'
export default () => (
)
```
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. This space is calculated as 40% of the icon's final computed
size (after considering `size`, `iconSize`, and `scaleIcon`). This margin is
applied to the right of an `icon` and to the left of an `iconAfter`.
```tsx
import { Button, Star } from 'tamagui'
export default () => (
<>
>
)
```
You can
[use the source of Button itself](https://github.com/tamagui/tamagui/blob/v2/code/ui/button/src/Button.tsx)
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.
```tsx
import { Button, ButtonDemo, YStack } from 'tamagui'
export default () => (
)
```
## Web Form Props
Button supports all standard HTML `
```
They accept your tokens/theme keys for color and size.
## Credit
The great [Lucide Icons](https://lucide.dev/), a superset of the wonderful [Feather Icons](https://feathericons.com/).
## components/lucide-icons/2.0.0
---
title: Lucide Icons
description: Cross-platform compatible SVG-based icons
name: lucide-icons
component: LucideIcons
package: lucide-icons
demoName: LucideIcons
---
## Installation
```sh
yarn add react-native-svg @tamagui/lucide-icons
```
## Usage
Use them as regular React components:
```tsx
import { Button } from 'tamagui'
import { Plus } from '@tamagui/lucide-icons'
// Button will automatically pass size/theme to icon
export default () => Hello world
// or you can control it
export default () => }>Hello world
```
They accept your tokens/theme keys for color and size.
## Credit
The great [Lucide Icons](https://lucide.dev/), a superset of the wonderful [Feather Icons](https://feathericons.com/).
## components/menu/2.0.0
---
title: Menu
description: A selectable list in a popover with nested submenus
name: dropdown menu
component: Menu
package: menu
---
```tsx hero template=Menu
```
Menu displays a list of actions or options in a floating panel triggered by a button. It supports nested submenus, keyboard navigation, native platform menus, and [automatically stacks](/ui/z-index) above other content.
## Installation
Menu is already installed in `tamagui`, or you can install it independently:
```bash
yarn add @tamagui/menu
```
If you want to use native menus, add these dependencies:
```sh
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:
```tsx
import '@tamagui/native/setup-zeego'
```
**Expo Router users:** This import must run _before_ `expo-router/entry`. Create an `index.js` at your project root that imports the setup first, then expo-router, and update your `package.json` main field to `"index.js"`. See the [upgrade guide](/docs/guides/how-to-upgrade#expo-router-entry-point) for details.
## Anatomy
Import all parts and piece them together.
```jsx
import { Menu } from 'tamagui' // or '@tamagui/menu'
export default () => (
)
```
## API Reference
### Menu
Contains every component for the Menu.
void',
required: false,
description: 'Called when the menu opens or closes.',
},
{
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',
default: '10',
required: false,
description: 'Distance between the menu and its trigger.',
},
{
name: 'resize',
type: 'boolean',
default: 'true',
required: false,
description: 'Constrains the menu to fit within available viewport space. When enabled, use Menu.ScrollView inside Content for scrollable overflow.',
},
{
name: 'unstyled',
required: false,
type: 'boolean',
description: 'Removes all default Tamagui styles.',
},
]}
/>
### Menu.Portal
Required for rendering the menu content.
### Menu.Trigger
The menu will only be triggered when the user right-clicks or long-presses
within the trigger area.
### Menu.Content
Contains the content of the menu.
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.',
},
]}
/>
### Menu.Item
A selectable menu item that triggers an action when selected.
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.',
},
]}
/>
### Menu.ItemTitle
Renders the title of the menu item.
You can directly pass a text node to the ItemTitle. However, if you use a nested
React node like ``, you need to pass `textValue` to the `` so that it
works with native menus.
### Menu.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` and `ios` props.
On iOS, it renders the native
[SF Symbols](https://github.com/andrewtavis/sf-symbols-online) icons.
```jsx line=1
```
### Menu.ItemImage
A component to render an item image. For native menus, it only works on iOS. It
takes the same props as `@tamagui/image`.
### Menu.ItemSubtitle
A component to render a subtitle for the menu item. For native menus, it only
works on iOS.
### Menu.Group
A component that groups multiple menu items together.
### Menu.CheckboxItem
A menu item with a checkbox that can be toggled on and off.
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 for native menus. Required when ItemTitle contains a React node.',
},
{
name: 'value',
type: "'on' | 'off' | 'mixed'",
required: false,
platform: 'ios/android',
description: 'Controlled checked state for native menus.',
},
{
name: 'onValueChange',
type: '(state, prevState) => void',
required: false,
platform: 'ios/android',
description: 'Called when checked state changes on native menus.',
},
{
name: 'checked',
type: 'boolean',
required: false,
description: 'Controlled checked state for web menus.',
},
{
name: 'onCheckedChange',
type: '(checked: boolean) => void',
required: false,
description: 'Called when checked state changes on web.',
},
]}
/>
### Menu.ItemIndicator
Use inside `Menu.CheckboxItem` or `Menu.RadioItem` to indicate when an item is checked.
This allows you to conditionally render a checkmark.
```jsx line=1
{/* This does not work with the native prop. */}
```
### Menu.Label
Renders a non-focusable label for a group of items. On native menus, only one
label is supported per menu and submenu.
### Menu.Arrow
Renders an arrow pointing to the trigger.
### Menu.Separator
Renders a visual divider between menu items. Web only.
### Menu.Sub
A container for nested submenu components.
void',
required: false,
description: 'Called when the submenu opens or closes.',
},
]}
/>
### Menu.SubContent
Renders the content of a submenu. Same props as `Menu.Content`, excluding `side` and
`align`.
### Menu.SubTrigger
A menu item that opens a submenu on hover or focus. Accepts the same props as
`Menu.Item`.
### Menu.ScrollView
A scrollable container for menu items. Use this inside `Menu.Content` when you have many items that may overflow. The menu automatically constrains to available viewport space (via `resize` prop), and ScrollView handles the overflow. Scrollbars are hidden by default.
```jsx
{/* Many menu items */}
```
## Styling
### Item Highlight Behavior
Menu items use `focusStyle` for highlighting rather than `hoverStyle`. This ensures a unified highlight experience when switching between mouse and keyboard navigation - only one item is ever highlighted at a time.
When you hover over an item, it receives focus, which triggers the `focusStyle`. When you use arrow keys to navigate, focus moves to the new item, removing the highlight from the previous one.
```jsx
// Default behavior - uses focusStyle for highlight
Settings
// Custom highlight styling - use focusStyle, not hoverStyle
Custom Highlight
```
Avoid using `hoverStyle` for background highlights on Menu.Item. This can cause "double
highlighting" when switching between mouse and keyboard - where both the hovered item
and the focused item appear highlighted simultaneously.
## components/native/2.0.0
---
title: Native UI
description: Optional native integrations for better performance and UX
name: native
---
# Native Integrations
Tamagui components work great out of the box, but several offer optional native
integrations for improved performance and platform-native UX. All native
integrations are opt-in - components work without them, just with slightly
different behavior.
## @tamagui/native Package
The `@tamagui/native` package provides setup utilities for native integrations.
Import the setup modules at your app's entry point, before any Tamagui imports.
```bash
npm install @tamagui/native
```
## Portal
**Native portals preserve React context** - the default implementation on native
uses a JS-based approach that breaks React context, or requires you to hoist data
awkwardly. With native portals, your custom contexts (navigation, app state)
work inside Sheet, Dialog, Popover, and other portaled content.
### Setup
```bash
npm install react-native-teleport
```
```tsx
// App.tsx - before any Tamagui imports
import '@tamagui/native/setup-teleport'
```
See [Portal docs](/docs/components/portal) for full details.
## Sheet Gestures
**Native gesture coordination** - makes sheets feel smoother and not get
confused with scrollable content during drags. Without this, scroll and pan
gestures can occasionally conflict on iOS.
### Setup
```bash
npm install react-native-gesture-handler
```
```tsx
// App.tsx - before any Tamagui imports
import '@tamagui/native/setup-gesture-handler'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
export default function App() {
return (
{/* Your app */}
)
}
```
See [Sheet docs](/docs/components/sheet) for full details.
## Menu & ContextMenu
**Native menus** - renders platform-native context menus instead of custom
overlays. Uses iOS's native menu API for haptics, blur effects, and system
integration.
### Setup
```bash
npm install zeego @react-native-menu/menu react-native-ios-context-menu react-native-ios-utilities sf-symbols-typescript
```
```tsx
// App.tsx - before any Tamagui imports
import '@tamagui/native/setup-zeego'
```
Then use the `native` prop:
```tsx
```
See [Menu docs](/docs/components/menu) and
[ContextMenu docs](/docs/components/context-menu) for full details.
## Toast
**Native toasts** - uses platform-native toast implementations:
- iOS: SPIndicator (system-style indicators)
- Android: ToastAndroid
- Web: Notification API
### Setup
```bash
npm install burnt
```
```tsx
// App.tsx - before any Tamagui imports
import '@tamagui/native/setup-burnt'
```
Then use the `native` prop on ToastProvider:
```tsx
{/* your app */}
```
See [Toast docs](/docs/components/toast) for full details.
## LinearGradient
**Native gradients** - uses `expo-linear-gradient` for high-performance native gradient rendering.
### Setup
```bash
npm install expo-linear-gradient
```
```tsx
// App.tsx - before any Tamagui imports
import '@tamagui/native/setup-expo-linear-gradient'
```
See [LinearGradient docs](/docs/components/linear-gradient) for full details.
## components/new-inputs/1.0.0
---
title: Input & Textarea
name: inputs
component: Input
demoName: Inputs
---
```tsx hero template=Inputs
```
Using Web APIs and relying on bare Tamagui with no `react-native-web` depedency on web compared to old Input component, support scaling all the styles up or down using the `size` property, and full `theme` support.
## Installation
LinearGradient is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/input
```
## Input
A one-line input field:
```tsx
import { Input } from 'tamagui'
export const App = () => (
// Accepts size and style properties directly
)
```
## TextArea
For multi-line inputs:
```tsx
import { TextArea } from 'tamagui'
export const App = () => (
// Accepts size and style properties directly
)
```
## components/new-inputs/2.0.0
---
title: Input & TextArea
description: Single-line and multi-line text inputs with web-first API
name: inputs
component: Input
package: input
demoName: Inputs
---
```tsx hero template=Inputs
```
The v2 Input uses web-standard HTML APIs as the primary interface, with automatic conversion to React Native equivalents on native platforms. This means you write web-first code that works everywhere.
## Installation
Input is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/input
```
## Usage
A single-line text input:
```tsx
import { Input } from 'tamagui'
export default () =>
```
For multi-line text input, use `TextArea`:
```tsx
import { TextArea } from 'tamagui'
export default () =>
```
## Web-First API
The v2 Input uses standard HTML input attributes. Here are the key props:
### Input Types
Use the standard HTML `type` attribute. On native, these automatically map to the appropriate keyboard and behavior:
```tsx
// Password input
// Email input (shows email keyboard on native)
// Phone number (shows phone pad on native)
// Number input (shows numeric keyboard on native)
// URL input
// Search input
```
**Cross-platform mapping:**
| Web `type` | Native behavior |
| ---------- | ------------------------------ |
| `password` | `secureTextEntry={true}` |
| `email` | `keyboardType="email-address"` |
| `tel` | `keyboardType="phone-pad"` |
| `number` | `keyboardType="numeric"` |
| `url` | `keyboardType="url"` |
| `search` | `inputMode="search"` |
### Enter Key Behavior
Use `enterKeyHint` to control the enter/return key label on virtual keyboards:
```tsx
```
On native, this automatically maps to `returnKeyType`.
### Form Attributes
Standard HTML form attributes work as expected:
```tsx
```
### Events
Use standard web events:
```tsx
console.log(e.target.value)}
onFocus={(e) => console.log('focused')}
onBlur={(e) => console.log('blurred')}
onKeyDown={(e) => {
if (e.key === 'Enter') {
// handle enter
}
}}
/>
```
For convenience, `onChangeText` is still supported but deprecated:
```tsx
// Deprecated - use onChange instead
setText(text)} />
// Preferred
setText(e.target.value)} />
```
### Submit Handling
For handling form submission on enter:
```tsx
{
console.log('Submitted:', e.nativeEvent.text)
}}
/>
```
## Styling
Input accepts all Tamagui style props and supports the `size` prop for consistent scaling:
```tsx
```
## Native-Only Props
Some props only apply on native platforms and have no web equivalent:
**keyboardAppearance (iOS)**: Controls the keyboard color scheme on iOS:
```tsx
```
**textContentType (iOS)**: Provides hints for iOS autofill:
```tsx
```
For web autofill, use the standard `autoComplete` attribute instead.
## Cross-Platform Text Behavior
These props work on both web and native with automatic value conversion:
### autoCorrect
Controls automatic spelling correction:
```tsx
// Boolean values (work everywhere)
// String values (web-style, converted on native)
```
### autoCapitalize
Controls automatic text capitalization. Native values provide more granular control:
```tsx
// Native-style values (recommended - work everywhere)
// No capitalization
// Capitalize first letter of sentences
// Capitalize first letter of each word
// Capitalize all characters
// Web-style values (mapped on native)
// Maps to "none" on native
// Maps to "sentences" on native
```
## Migration from v1
If you're migrating from v1 Input, here are the key changes:
| v1 (React Native style) | v2 (Web style) |
| ------------------------------ | ---------------------------- |
| `secureTextEntry` | `type="password"` |
| `keyboardType="email-address"` | `type="email"` |
| `keyboardType="phone-pad"` | `type="tel"` |
| `keyboardType="numeric"` | `type="number"` |
| `keyboardType="url"` | `type="url"` |
| `returnKeyType="search"` | `enterKeyHint="search"` |
| `editable={false}` | `readOnly` or `disabled` |
| `onChangeText` | `onChange` |
| `multiline` | Use `TextArea` or `rows > 1` |
| `numberOfLines` | `rows` |
The v1 props still work but are deprecated. We recommend updating to the web-standard props for better cross-platform consistency.
## API Reference
### Input Props
Accepts all HTML `` attributes plus Tamagui style props.
void',
description: 'Called when enter/return is pressed.',
},
{
name: 'keyboardAppearance',
required: false,
type: '"default" | "light" | "dark"',
description: 'iOS only. Controls keyboard color scheme.',
},
{
name: 'textContentType',
required: false,
type: 'string',
description: 'iOS only. Hints for autofill. Use autoComplete for web.',
},
]}
/>
### TextArea Props
Accepts all Input props plus:
## components/popover/1.0.0
---
title: Popover
description: A simple popover component
name: popover
component: Popover
package: popover
demoName: Popover
---
# Popover
Show content with a trigger in a floating pane.
```tsx hero template=Popover
```
Popovers are a great way to show content that's only visible when trigger is pressed, floating above the current content.
Support for native was contributed by a community member, but not guaranteed to work
until we get time to fully test and improve native interactions. We don't recommend the
Popover pattern for phone-sized devices either way, and instead you can adapt it to a
Sheet.
## Installation
Popover is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/popover
```
## Anatomy
```tsx
import { Popover } from 'tamagui' // or '@tamagui/popover'
export default () => (
{/* ScrollView is optional, can just put any contents inside if not scrollable */}
{/* ... */}
{/* ... */}
{/* optionally change to sheet when small screen */}
)
```
## API Reference
### Popover
Contains every component for the popover.
void',
required: false,
},
{
name: 'modal',
type: 'boolean',
default: 'true',
required: false,
description: `Renders into root of app instead of inline.`,
},
{
name: 'stayInFrame',
type: 'ShiftProps | boolean',
required: false,
description: `Keeps the Popover inside the frame, see floating-ui shift().`,
},
{
name: 'allowFlip',
type: 'FlipProps | boolean',
required: false,
description: `Moves the Popover to other sides when space allows it, see floating-ui flip().`,
},
{
name: 'offset',
type: 'OffsetOptions',
required: false,
description: `Determines the distance the Popover appears from the target, see floating-ui offset().`,
},
{
name: 'unstyled',
required: false,
type: `boolean`,
description: `Removes all default Tamagui styles.`,
},
]}
/>
### Popover.Trigger
Used to trigger opening of the popover when uncontrolled, just renders a YStack, see [Stacks](/docs/components/stacks).
### Popover.Content
Renders as SizableStack which is just a YStack (see [Stacks](/docs/components/stacks)) with an extra `size` prop that accepts any `SizeTokens`.
Used to display the content of the popover.
### Popover.Anchor
Renders as YStack, see [Stacks](/docs/components/stacks).
When you want the Trigger to be in another location from where the Popover attaches, use Anchor. When used, Anchor is where the Popover will attach, while Trigger will open it.
### Popover.Sheet
When used with `Adapt`, Popover will render as a sheet when that breakpoint is active.
See [Sheet](/docs/components/sheet) for more props.
Must use `Adapt.Contents` inside the `Popover.Sheet.Frame` to insert the contents given to `Popover.Content`
### Popover.ScrollView
Must be nested inside Content. Renders as a plain React Native ScrollView. If used alongside `` and Sheet, Tamagui will automatically know to remove this ScrollView when swapping into the Sheet, as the Sheet must use it's own ScrollView that handles special logic for interactions with dragging.
## components/popover/1.110.0
---
title: Popover
description: Show content in a floating pane.
name: popover
component: Popover
package: popover
demoName: Popover
---
```tsx hero template=Popover
```
Popovers are a great way to show content that's only visible when trigger is pressed, floating above the current content.
## Installation
Popover is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/popover
```
### PortalProvider
When rendering into root of app instead of inline, you'll first need to install the `@tamagui/portal` package:
```bash
npm install @tamagui/portal
```
Then add `PortalProvider` to the root of your app:
```tsx fileName="App.tsx"
import { PortalProvider } from '@tamagui/portal'
import YourApp from './components/YourApp'
function App() {
return (
)
}
export default App
```
## Anatomy
```tsx
import { Popover, Adapt } from 'tamagui' // or '@tamagui/popover'
export default () => (
{/* ScrollView is optional, can just put any contents inside if not scrollable */}
{/* ... */}
{/* ... */}
{/* optionally change to sheet when small screen */}
{/* you can also use */}
)
```
## API Reference
### Popover
Contains every component for the popover.
void',
required: false,
},
{
name: 'keepChildrenMounted',
type: 'boolean',
required: false,
description: `By default, Popover removes children from DOM/rendering when fully hidden. Setting true will keep children mounted even when hidden. This can be beneficial for performance if your popover content is expensive to render.`,
},
{
name: 'stayInFrame',
type: 'ShiftProps | boolean',
required: false,
description: `Keeps the Popover inside the frame, see floating-ui shift().`,
},
{
name: 'allowFlip',
type: 'FlipProps | boolean',
required: false,
description: `Moves the Popover to other sides when space allows it, see floating-ui flip().`,
},
{
name: 'offset',
type: 'OffsetOptions',
required: false,
description: `Determines the distance the Popover appears from the target, see floating-ui offset().`,
},
{
name: 'hoverable',
type: 'boolean | UseFloatingProps',
required: false,
description: `Allows hovering on the trigger to open the popover. See UseFloatingProps from floating-ui: accepts boolean or object of { delay: number, restMs: number, handleClose: Function, mouseOnly: boolean, move: boolean }`,
},
]}
/>
If using `modal={true}` (which is `true` by default), refer to the [PortalProvider
installation](/ui/popover/1.83.0#portalprovider) for more information.
### Popover.Arrow
Popover.Arrow can be used to show an arrow that points at the Trigger element. In order for the Arrow to show you must have a Trigger element within your Popover. Arrows extend YStack, see [Stacks](/docs/components/stacks).
### Popover.Trigger
Used to trigger opening of the popover when uncontrolled, just renders a YStack, see [Stacks](/docs/components/stacks).
### Popover.Content
Renders as SizableStack which is just a YStack (see [Stacks](/docs/components/stacks)) with an extra `size` prop that accepts any `SizeTokens`.
Used to display the content of the popover.
### Popover.Anchor
Renders as YStack, see [Stacks](/docs/components/stacks).
When you want the Trigger to be in another location from where the Popover attaches, use Anchor. When used, Anchor is where the Popover will attach, while Trigger will open it.
### Popover.Sheet
When used with `Adapt`, Popover will render as a sheet when that breakpoint is active.
See [Sheet](/docs/components/sheet) for more props.
Must use `Adapt.Contents` inside the `Popover.Sheet.Frame` to insert the contents given to `Popover.Content`
### Popover.ScrollView
Must be nested inside Content. Renders as a plain React Native ScrollView. If used alongside `` and Sheet, Tamagui will automatically know to remove this ScrollView when swapping into the Sheet, as the Sheet must use it's own ScrollView that handles special logic for interactions with dragging.
## components/popover/1.125.0
---
title: Popover
description: Show content with a trigger in a floating pane.
name: popover
component: Popover
package: popover
demoName: Popover
---
```tsx hero template=Popover
```
Popovers are a great way to show content that's only visible when trigger is pressed, floating above the current content.
Note: Popovers are not a recommended pattern for mobile apps, and so aren't supported on
native. Instead you can use Adapt and render them as a Sheet, or just conditionally
render them. We landed support for them at one point, but we need the community to
contribute tests in order to support them for mobile again.
## Installation
Popover is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/popover
```
### PortalProvider
When rendering into root of app instead of inline, you'll first need to install the `@tamagui/portal` package:
```bash
npm install @tamagui/portal
```
Then add `PortalProvider` to the root of your app:
```tsx fileName="App.tsx"
import { PortalProvider } from '@tamagui/portal'
import YourApp from './components/YourApp'
function App() {
return (
)
}
export default App
```
## Anatomy
```tsx
import { Popover, Adapt } from 'tamagui' // or '@tamagui/popover'
export default () => (
{/* ScrollView is optional, can just put any contents inside if not scrollable */}
{/* ... */}
{/* ... */}
{/* optionally change to sheet when small screen */}
{/* you can also use */}
)
```
## API Reference
### Popover
Contains every component for the popover.
void',
required: false,
},
{
name: 'keepChildrenMounted',
type: 'boolean',
required: false,
description: `By default, Popover removes children from DOM/rendering when fully hidden. Setting true will keep children mounted even when hidden. This can be beneficial for performance if your popover content is expensive to render.`,
},
{
name: 'stayInFrame',
type: 'ShiftProps | boolean',
required: false,
description: `Keeps the Popover inside the frame, see floating-ui shift().`,
},
{
name: 'allowFlip',
type: 'FlipProps | boolean',
required: false,
description: `Moves the Popover to other sides when space allows it, see floating-ui flip().`,
},
{
name: 'offset',
type: 'OffsetOptions',
required: false,
description: `Determines the distance the Popover appears from the target, see floating-ui offset().`,
},
{
name: 'hoverable',
type: 'boolean | UseFloatingProps',
required: false,
description: `Allows hovering on the trigger to open the popover. See UseFloatingProps from floating-ui: accepts boolean or object of { delay: number, restMs: number, handleClose: Function, mouseOnly: boolean, move: boolean }`,
},
{
name: 'resize',
type: 'SizeProps | boolean',
required: false,
description: `Will set maxWidth and maxHeight of Content to fit inside outer window when it won't fit, see floating-ui size().`,
},
]}
/>
For most of these properties, you'll want to reference the [floating-ui docs](https://floating-ui.com/docs/getting-started).
If using `modal={true}` (which is `true` by default), refer to the [PortalProvider
installation](/ui/popover/1.83.0#portalprovider) for more information.
### Popover.Arrow
Popover.Arrow can be used to show an arrow that points at the Trigger element. In order for the Arrow to show you must have a Trigger element within your Popover. Arrows extend YStack, see [Stacks](/docs/components/stacks).
### Popover.Trigger
Used to trigger opening of the popover when uncontrolled, just renders a YStack, see [Stacks](/docs/components/stacks).
### Popover.Content
Renders as SizableStack which is just a YStack (see [Stacks](/docs/components/stacks)) with an extra `size` prop that accepts any `SizeTokens`.
Used to display the content of the popover.
### Popover.Anchor
Renders as YStack, see [Stacks](/docs/components/stacks).
When you want the Trigger to be in another location from where the Popover attaches, use Anchor. When used, Anchor is where the Popover will attach, while Trigger will open it.
### Popover.Sheet
When used with `Adapt`, Popover will render as a sheet when that breakpoint is active.
See [Sheet](/docs/components/sheet) for more props.
Must use `Adapt.Contents` inside the `Popover.Sheet.Frame` to insert the contents given to `Popover.Content`
### Popover.ScrollView
Must be nested inside Content. Renders as a plain React Native ScrollView. If used alongside `` and Sheet, Tamagui will automatically know to remove this ScrollView when swapping into the Sheet, as the Sheet must use it's own ScrollView that handles special logic for interactions with dragging.
## components/popover/1.128.0
---
title: Popover
description: Show content with a trigger in a floating pane.
name: popover
component: Popover
package: popover
demoName: Popover
---
```tsx hero template=Popover
```
Popovers are a great way to show content that's only visible when trigger is
pressed, floating above the current content.
Note: Popovers are not a recommended pattern for mobile apps, and so aren't supported on
native. Instead you can use Adapt and render them as a Sheet, or just conditionally
render them. We landed support for them at one point, but we need the community to
contribute tests in order to support them for mobile again.
## Installation
Popover is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/popover
```
### PortalProvider
When rendering into root of app instead of inline, you'll first need to install
the `@tamagui/portal` package:
```bash
npm install @tamagui/portal
```
Then add `PortalProvider` to the root of your app:
```tsx fileName="App.tsx"
import { PortalProvider } from '@tamagui/portal'
import YourApp from './components/YourApp'
function App() {
return (
)
}
export default App
```
## Anatomy
```tsx
import { Popover, Adapt } from 'tamagui' // or '@tamagui/popover'
export default () => (
{/* Optional: Control focus behavior */}
{/* ScrollView is optional, can just put any contents inside if not scrollable */}
{/* ... */}
{/* ... */}
{/* optionally change to sheet when small screen */}
{/* you can also use */}
)
```
## API Reference
### Popover
Contains every component for the popover.
void',
required: false,
},
{
name: 'keepChildrenMounted',
type: 'boolean',
required: false,
description: `By default, Popover removes children from DOM/rendering when fully hidden. Setting true will keep children mounted even when hidden. This can be beneficial for performance if your popover content is expensive to render.`,
},
{
name: 'stayInFrame',
type: 'ShiftProps | boolean',
required: false,
description: `Keeps the Popover inside the frame, see floating-ui shift().`,
},
{
name: 'allowFlip',
type: 'FlipProps | boolean',
required: false,
description: `Moves the Popover to other sides when space allows it, see floating-ui flip().`,
},
{
name: 'offset',
type: 'OffsetOptions',
required: false,
description: `Determines the distance the Popover appears from the target, see floating-ui offset().`,
},
{
name: 'hoverable',
type: 'boolean | UseFloatingProps',
required: false,
description: `Allows hovering on the trigger to open the popover. See UseFloatingProps from floating-ui: accepts boolean or object of { delay: number, restMs: number, handleClose: Function, mouseOnly: boolean, move: boolean }`,
},
{
name: 'resize',
type: 'SizeProps | boolean',
required: false,
description: `Will set maxWidth and maxHeight of Content to fit inside outer window when it won't fit, see floating-ui size().`,
},
]}
/>
For most of these properties, you'll want to reference the
[floating-ui docs](https://floating-ui.com/docs/getting-started).
If using `modal={true}` (which is `true` by default), refer to the [PortalProvider
installation](/ui/popover/1.83.0#portalprovider) for more information.
### Popover.Arrow
Popover.Arrow can be used to show an arrow that points at the Trigger element.
In order for the Arrow to show you must have a Trigger element within your
Popover. Arrows extend YStack, see [Stacks](/docs/components/stacks).
### Popover.Trigger
Used to trigger opening of the popover when uncontrolled, just renders a YStack,
see [Stacks](/docs/components/stacks).
### Popover.Content
Extends PopperContent which extends SizableStack which extends a YStack (see
[Stacks](/docs/components/stacks)).
Also extends
Used to display the content of the popover.
### Popover.Anchor
Renders as YStack, see [Stacks](/docs/components/stacks).
When you want the Trigger to be in another location from where the Popover
attaches, use Anchor. When used, Anchor is where the Popover will attach, while
Trigger will open it.
### Popover.Sheet
When used with `Adapt`, Popover will render as a sheet when that breakpoint is
active.
See [Sheet](/docs/components/sheet) for more props.
Must use `Adapt.Contents` inside the `Popover.Sheet.Frame` to insert the
contents given to `Popover.Content`
### Popover.FocusScope
Provides access to the underlying FocusScope component used by Popover for focus
management. Can be used to control focus behavior from a parent component.
void',
description: `Event handler called when auto-focusing on mount. Can be prevented`,
},
{
name: 'onUnmountAutoFocus',
type: '(event: Event) => void',
description: `Event handler called when auto-focusing on unmount. Can be prevented`,
},
]}
/>
### Popover.ScrollView
Must be nested inside Content. Renders as a plain React Native ScrollView. If
used alongside `` and Sheet, Tamagui will automatically know to remove
this ScrollView when swapping into the Sheet, as the Sheet must use it's own
ScrollView that handles special logic for interactions with dragging.
## components/popover/1.129.0
---
title: Popover
description: Show content with a trigger in a floating pane.
name: popover
component: Popover
package: popover
demoName: Popover
---
```tsx hero template=Popover
```
Popovers are a great way to show content that's only visible when trigger is
pressed, floating above the current content.
Note: Popovers are not a recommended pattern for mobile apps, and so aren't supported on
native. Instead you can use Adapt and render them as a Sheet, or just conditionally
render them. We landed support for them at one point, but we need the community to
contribute tests in order to support them for mobile again.
## Installation
Popover is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/popover
```
### PortalProvider
When rendering into root of app instead of inline, you'll first need to install
the `@tamagui/portal` package:
```bash
npm install @tamagui/portal
```
Then add `PortalProvider` to the root of your app:
```tsx fileName="App.tsx"
import { PortalProvider } from '@tamagui/portal'
import YourApp from './components/YourApp'
function App() {
return (
)
}
export default App
```
## Anatomy
```tsx
import { Popover, Adapt } from 'tamagui' // or '@tamagui/popover'
export default () => (
{/* Optional: Control focus behavior */}
{/* ScrollView is optional, can just put any contents inside if not scrollable */}
{/* ... */}
{/* ... */}
{/* optionally change to sheet when small screen */}
{/* you can also use */}
)
```
## API Reference
### Popover
Contains every component for the popover.
void',
required: false,
},
{
name: 'keepChildrenMounted',
type: 'boolean | "lazy"',
required: false,
description: `By default, Popover removes children from DOM/rendering when fully hidden. Setting true will keep children mounted even when hidden. This can be beneficial for performance if your popover content is expensive to render. The "lazy" value will only initially mount the children after a React startTransition, and then keep them mounted thereafter.`,
},
{
name: 'stayInFrame',
type: 'ShiftProps | boolean',
required: false,
description: `Keeps the Popover inside the frame, see floating-ui shift().`,
},
{
name: 'allowFlip',
type: 'FlipProps | boolean',
required: false,
description: `Moves the Popover to other sides when space allows it, see floating-ui flip().`,
},
{
name: 'offset',
type: 'OffsetOptions',
required: false,
description: `Determines the distance the Popover appears from the target, see floating-ui offset().`,
},
{
name: 'hoverable',
type: 'boolean | UseFloatingProps',
required: false,
description: `Allows hovering on the trigger to open the popover. See UseFloatingProps from floating-ui: accepts boolean or object of { delay: number, restMs: number, handleClose: Function, mouseOnly: boolean, move: boolean }`,
},
{
name: 'resize',
type: 'SizeProps | boolean',
required: false,
description: `Will set maxWidth and maxHeight of Content to fit inside outer window when it won't fit, see floating-ui size().`,
},
]}
/>
For most of these properties, you'll want to reference the
[floating-ui docs](https://floating-ui.com/docs/getting-started).
If using `modal={true}` (which is `true` by default), refer to the [PortalProvider
installation](/ui/popover/1.83.0#portalprovider) for more information.
### Popover.Arrow
Popover.Arrow can be used to show an arrow that points at the Trigger element.
In order for the Arrow to show you must have a Trigger element within your
Popover. Arrows extend YStack, see [Stacks](/docs/components/stacks).
### Popover.Trigger
Used to trigger opening of the popover when uncontrolled, just renders a YStack,
see [Stacks](/docs/components/stacks).
### Popover.Content
Extends PopperContent which extends SizableStack which extends a YStack (see
[Stacks](/docs/components/stacks)).
Also extends
Used to display the content of the popover.
### Popover.Anchor
Renders as YStack, see [Stacks](/docs/components/stacks).
When you want the Trigger to be in another location from where the Popover
attaches, use Anchor. When used, Anchor is where the Popover will attach, while
Trigger will open it.
### Popover.Sheet
When used with `Adapt`, Popover will render as a sheet when that breakpoint is
active.
See [Sheet](/docs/components/sheet) for more props.
Must use `Adapt.Contents` inside the `Popover.Sheet.Frame` to insert the
contents given to `Popover.Content`
### Popover.FocusScope
Provides access to the underlying FocusScope component used by Popover for focus
management. Can be used to control focus behavior from a parent component.
void',
description: `Event handler called when auto-focusing on mount. Can be prevented`,
},
{
name: 'onUnmountAutoFocus',
type: '(event: Event) => void',
description: `Event handler called when auto-focusing on unmount. Can be prevented`,
},
]}
/>
### Popover.ScrollView
Must be nested inside Content. Renders as a plain React Native ScrollView. If
used alongside `` and Sheet, Tamagui will automatically know to remove
this ScrollView when swapping into the Sheet, as the Sheet must use it's own
ScrollView that handles special logic for interactions with dragging.
## components/popover/1.131.0
---
title: Popover
description: Show content with a trigger in a floating pane.
name: popover
component: Popover
package: popover
demoName: Popover
---
```tsx hero template=Popover
```
Popovers are a great way to show content that's only visible when trigger is
pressed, floating above the current content. Be sure to open the code example
above for a copy-paste implementation.
Note: Popovers are not a recommended pattern for mobile apps. Instead you can use Adapt
and render them as a Sheet, or just conditionally render them to some native UI.
## Installation
Popover is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/popover
```
### PortalProvider
_Only_ if you are not using `tamagui` and installing popover independently -
you'll need to set up the portal for it with the `@tamagui/portal` package:
```bash
npm install @tamagui/portal
```
Then add `PortalProvider` to the root of your app:
```tsx fileName="App.tsx"
import { PortalProvider } from '@tamagui/portal'
import YourApp from './components/YourApp'
function App() {
return (
)
}
export default App
```
## Anatomy
```tsx
import { Popover, Adapt } from 'tamagui' // or '@tamagui/popover'
export default () => (
{/* Optional: Control focus behavior */}
{/* ScrollView is optional, can just put any contents inside if not scrollable */}
{/* ... */}
{/* ... */}
{/* optionally change to sheet when small screen */}
{/* you can also use */}
)
```
## Scoping
Popover supports scoping which lets you mount one or more Popover instances at
the root of your app, while having a deeply nested child Trigger or Content
attach to the proper parent Popover instance.
In performance sensitive areas you may want to take advantage of this as it allows
you to only render the Popover.Trigger inside the sensitive area.
Popover isn't the cheapest component - it has a lot of functionality
inside of it like scroll management, focus management, and tracking position.
Here's the basic anatomy of using `scope` and placing your Popover higher up
for performance:
```tsx fileName=_layout.tsx
import { Popover } from 'tamagui'
// in your root layout:
export default ({ children }) => (
{/* ... */}
{/* the rest of your app, note that it's inside of Popover */}
{children}
)
```
```tsx fileName=UserAvatar.tsx
export default () => (
)
```
Note that the `Trigger` scope ties to the `Popover` scope.
## API Reference
### Popover
Contains every component for the popover.
void',
required: false,
},
{
name: 'keepChildrenMounted',
type: 'boolean | "lazy"',
required: false,
description: `By default, Popover removes children from DOM/rendering when fully hidden. Setting true will keep children mounted even when hidden. This can be beneficial for performance if your popover content is expensive to render. The "lazy" value will only initially mount the children after a React startTransition, and then keep them mounted thereafter.`,
},
{
name: 'stayInFrame',
type: 'ShiftProps | boolean',
required: false,
description: `Keeps the Popover inside the frame, see floating-ui shift().`,
},
{
name: 'allowFlip',
type: 'FlipProps | boolean',
required: false,
description: `Moves the Popover to other sides when space allows it, see floating-ui flip().`,
},
{
name: 'offset',
type: 'OffsetOptions',
required: false,
description: `Determines the distance the Popover appears from the target, see floating-ui offset().`,
},
{
name: 'hoverable',
type: 'boolean | UseFloatingProps',
required: false,
description: `Allows hovering on the trigger to open the popover. See UseFloatingProps from floating-ui: accepts boolean or object of { delay: number, restMs: number, handleClose: Function, mouseOnly: boolean, move: boolean }`,
},
{
name: 'resize',
type: 'SizeProps | boolean',
required: false,
description: `Will set maxWidth and maxHeight of Content to fit inside outer window when it won't fit, see floating-ui size().`,
},
]}
/>
For most of these properties, you'll want to reference the
[floating-ui docs](https://floating-ui.com/docs/getting-started).
If using `modal={true}` (which is `true` by default), refer to the [PortalProvider
installation](#portalprovider) for more information.
### Popover.Arrow
Popover.Arrow can be used to show an arrow that points at the Trigger element.
In order for the Arrow to show you must have a Trigger element within your
Popover. Arrows extend YStack, see [Stacks](/docs/components/stacks).
### Popover.Trigger
Used to trigger opening of the popover when uncontrolled, just renders a YStack,
see [Stacks](/docs/components/stacks).
### Popover.Content
Extends PopperContent which extends SizableStack which extends a YStack (see
[Stacks](/docs/components/stacks)).
Also extends
Used to display the content of the popover.
### Popover.Anchor
Renders as YStack, see [Stacks](/docs/components/stacks).
When you want the Trigger to be in another location from where the Popover
attaches, use Anchor. When used, Anchor is where the Popover will attach, while
Trigger will open it.
### Popover.Sheet
When used with `Adapt`, Popover will render as a sheet when that breakpoint is
active.
See [Sheet](/docs/components/sheet) for more props.
Must use `Adapt.Contents` inside the `Popover.Sheet.Frame` to insert the
contents given to `Popover.Content`
### Popover.FocusScope
Provides access to the underlying FocusScope component used by Popover for focus
management. Can be used to control focus behavior from a parent component.
void',
description: `Event handler called when auto-focusing on mount. Can be prevented`,
},
{
name: 'onUnmountAutoFocus',
type: '(event: Event) => void',
description: `Event handler called when auto-focusing on unmount. Can be prevented`,
},
]}
/>
### Popover.ScrollView
Must be nested inside Content. Renders as a plain React Native ScrollView. If
used alongside `` and Sheet, Tamagui will automatically know to remove
this ScrollView when swapping into the Sheet, as the Sheet must use its own
ScrollView that handles special logic for interactions with dragging.
## components/popover/1.43.0
---
title: Popover
description: A simple popover component
name: popover
component: Popover
package: popover
demoName: Popover
---
# Popover
Show content with a trigger in a floating pane
```tsx hero template=Popover
```
Popovers are a great way to show content that's only visible when trigger is pressed, floating above the current content.
Support for native was contributed by a community member, but not guaranteed to work
until we get time to fully test. We don't recommend the Popover pattern for phone-sized
devices, and you can adapt it to a Sheet instead.
## Installation
Popover is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/popover
```
## Anatomy
```tsx
import { Popover } from 'tamagui' // or '@tamagui/popover'
export default () => (
{/* ScrollView is optional, can just put any contents inside if not scrollable */}
{/* ... */}
{/* ... */}
{/* optionally change to sheet when small screen */}
)
```
## API Reference
### Popover
Contains every component for the popover.
void',
required: false,
},
{
name: 'modal',
type: 'boolean',
default: 'true',
required: false,
description: `Renders into root of app instead of inline.`,
},
{
name: 'keepChildrenMounted',
type: 'boolean',
required: false,
description: `By default, Popover removes children from DOM/rendering when fully hidden. Setting true will keep children mounted even when hidden. This can be beneficial for performance if your popover content is expensive to render.`,
},
{
name: 'stayInFrame',
type: 'ShiftProps | boolean',
required: false,
description: `Keeps the Popover inside the frame, see floating-ui shift().`,
},
{
name: 'allowFlip',
type: 'FlipProps | boolean',
required: false,
description: `Moves the Popover to other sides when space allows it, see floating-ui flip().`,
},
{
name: 'offset',
type: 'OffsetOptions',
required: false,
description: `Determines the distance the Popover appears from the target, see floating-ui offset().`,
},
]}
/>
### Popover.Trigger
Used to trigger opening of the popover when uncontrolled, just renders a YStack, see [Stacks](/docs/components/stacks).
### Popover.Content
Renders as SizableStack which is just a YStack (see [Stacks](/docs/components/stacks)) with an extra `size` prop that accepts any `SizeTokens`.
Used to display the content of the popover.
### Popover.Anchor
Renders as YStack, see [Stacks](/docs/components/stacks).
When you want the Trigger to be in another location from where the Popover attaches, use Anchor. When used, Anchor is where the Popover will attach, while Trigger will open it.
### Popover.Sheet
When used with `Adapt`, Popover will render as a sheet when that breakpoint is active.
See [Sheet](/docs/components/sheet) for more props.
Must use `Adapt.Contents` inside the `Popover.Sheet.Frame` to insert the contents given to `Popover.Content`
### Popover.ScrollView
Must be nested inside Content. Renders as a plain React Native ScrollView. If used alongside `` and Sheet, Tamagui will automatically know to remove this ScrollView when swapping into the Sheet, as the Sheet must use it's own ScrollView that handles special logic for interactions with dragging.
## components/popover/1.83.0
---
title: Popover
description: A simple popover component
name: popover
component: Popover
package: popover
demoName: Popover
---
# Popover
Show content with a trigger in a floating pane
```tsx hero template=Popover
```
Popovers are a great way to show content that's only visible when trigger is pressed, floating above the current content.
## Installation
Popover is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/popover
```
### PortalProvider
When rendering into root of app instead of inline, you'll first need to install the `@tamagui/portal` package:
```bash
npm install @tamagui/portal
```
Then add `PortalProvider` to the root of your app:
```tsx fileName="App.tsx"
import { PortalProvider } from '@tamagui/portal'
import YourApp from './components/YourApp'
function App() {
return (
)
}
export default App
```
## Anatomy
```tsx
import { Popover, Adapt } from 'tamagui' // or '@tamagui/popover'
export default () => (
{/* ScrollView is optional, can just put any contents inside if not scrollable */}
{/* ... */}
{/* ... */}
{/* optionally change to sheet when small screen */}
{/* you can also use */}
)
```
## API Reference
### Popover
Contains every component for the popover.
void',
required: false,
},
{
name: 'modal',
type: 'boolean',
default: 'true',
required: false,
description: `Renders into root of app instead of inline.`,
},
{
name: 'keepChildrenMounted',
type: 'boolean',
required: false,
description: `By default, Popover removes children from DOM/rendering when fully hidden. Setting true will keep children mounted even when hidden. This can be beneficial for performance if your popover content is expensive to render.`,
},
{
name: 'stayInFrame',
type: 'ShiftProps | boolean',
required: false,
description: `Keeps the Popover inside the frame, see floating-ui shift().`,
},
{
name: 'allowFlip',
type: 'FlipProps | boolean',
required: false,
description: `Moves the Popover to other sides when space allows it, see floating-ui flip().`,
},
{
name: 'offset',
type: 'OffsetOptions',
required: false,
description: `Determines the distance the Popover appears from the target, see floating-ui offset().`,
},
{
name: 'hoverable',
type: 'boolean | UseFloatingProps',
required: false,
description: `Allows hovering on the trigger to open the popover. See UseFloatingProps from floating-ui: accepts boolean or object of { delay: number, restMs: number, handleClose: Function, mouseOnly: boolean, move: boolean }`,
},
]}
/>
If using `modal={true}` (which is `true` by default), refer to the [PortalProvider
installation](/ui/popover/1.83.0#portalprovider) for more information.
### Popover.Arrow
Popover.Arrow can be used to show an arrow that points at the Trigger element. In order for the Arrow to show you must have a Trigger element within your Popover. Arrows extend YStack, see [Stacks](/docs/components/stacks).
### Popover.Trigger
Used to trigger opening of the popover when uncontrolled, just renders a YStack, see [Stacks](/docs/components/stacks).
### Popover.Content
Renders as SizableStack which is just a YStack (see [Stacks](/docs/components/stacks)) with an extra `size` prop that accepts any `SizeTokens`.
Used to display the content of the popover.
### Popover.Anchor
Renders as YStack, see [Stacks](/docs/components/stacks).
When you want the Trigger to be in another location from where the Popover attaches, use Anchor. When used, Anchor is where the Popover will attach, while Trigger will open it.
### Popover.Sheet
When used with `Adapt`, Popover will render as a sheet when that breakpoint is active.
See [Sheet](/docs/components/sheet) for more props.
Must use `Adapt.Contents` inside the `Popover.Sheet.Frame` to insert the contents given to `Popover.Content`
### Popover.ScrollView
Must be nested inside Content. Renders as a plain React Native ScrollView. If used alongside `` and Sheet, Tamagui will automatically know to remove this ScrollView when swapping into the Sheet, as the Sheet must use it's own ScrollView that handles special logic for interactions with dragging.
## components/popover/2.0.0
---
title: Popover
description: Show content with a trigger in a floating pane
name: popover
component: Popover
package: popover
demoName: Popover
---
```tsx hero template=Popover
```
Popovers are a great way to show content that's only visible when trigger is
pressed, floating above the current content. They [automatically stack](/ui/z-index) above other content. Be sure to open the code example above for a copy-paste implementation.
Note: Popovers are not a recommended pattern for mobile apps. Instead you can use Adapt
and render them as a Sheet, or just conditionally render them to some native UI.
## Installation
Popover is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/popover
```
For native apps, we recommend [setting up native
portals](/docs/components/portal#native-portal-setup-recommended) to preserve React
context inside Popover content.
## Anatomy
```tsx
import { Popover, Adapt, Sheet } from 'tamagui' // or '@tamagui/popover'
export default () => (
{/* Optional: Control focus behavior */}
{/* ScrollView is optional, can just put any contents inside if not scrollable */}
{/* ... */}
{/* ... */}
{/* optionally change to sheet when small screen */}
{/* you can also use */}
)
```
## Scoping
Popover supports scoping which lets you mount one or more Popover instances at
the root of your app, while having a deeply nested child Trigger or Content
attach to the proper parent Popover instance.
In performance sensitive areas you may want to take advantage of this as it allows
you to only render the Popover.Trigger inside the sensitive area.
Popover isn't the cheapest component - it has a lot of functionality
inside of it like scroll management, focus management, and tracking position.
Here's the basic anatomy of using `scope` and placing your Popover higher up
for performance:
```tsx fileName=_layout.tsx
import { Popover } from 'tamagui'
// in your root layout:
export default ({ children }) => (
{/* ... */}
{/* the rest of your app, note that it's inside of Popover */}
{children}
)
```
```tsx fileName=UserAvatar.tsx
export default () => (
)
```
Note that the `Trigger` scope ties to the `Popover` scope.
## API Reference
### Popover
Contains every component for the popover.
void`,
required: false,
description: `Called when the popover opens or closes. The optional second argument indicates how it was triggered - 'hover' for hover events (when using the hoverable prop) or 'press' for click/press events.`,
},
{
name: 'keepChildrenMounted',
type: 'boolean | "lazy"',
required: false,
description: `By default, Popover removes children from DOM/rendering when fully hidden. Setting true will keep children mounted even when hidden. This can be beneficial for performance if your popover content is expensive to render. The "lazy" value will only initially mount the children after a React startTransition, and then keep them mounted thereafter.`,
},
{
name: 'disableDismissable',
type: 'boolean',
required: false,
description: `Disables the dismissable layer (escape key, outside click handling). Useful when using keepChildrenMounted for popovers that stay mounted but are visually hidden - set this to true when the popover is hidden to prevent it from capturing escape key presses.`,
},
{
name: 'stayInFrame',
type: 'ShiftProps | boolean',
required: false,
default: '{ padding: 10 }',
description: `Shifts the popover horizontally to stay within viewport bounds. Pass an object to customize shift behavior (mainAxis, crossAxis, padding).`,
},
{
name: 'allowFlip',
type: 'FlipProps | boolean',
required: false,
description: `Moves the Popover to other sides when space allows it, see floating-ui flip().`,
},
{
name: 'offset',
type: 'OffsetOptions',
required: false,
description: `Determines the distance the Popover appears from the target, see floating-ui offset().`,
},
{
name: 'hoverable',
type: 'boolean | UseFloatingProps',
required: false,
description: `Allows hovering on the trigger to open the popover. See UseFloatingProps from floating-ui: accepts boolean or object of { delay: number, restMs: number, handleClose: Function, mouseOnly: boolean, move: boolean }`,
},
{
name: 'resize',
type: 'SizeProps | boolean',
required: false,
description: `Will set maxWidth and maxHeight of Content to fit inside outer window when it won't fit, see floating-ui size().`,
},
{
name: 'zIndex',
type: 'number',
required: false,
description: `Override the automatic z-index stacking. By default, Tamagui automatically stacks overlays so later-opened content appears above earlier content. Only set this if you need to override the automatic behavior.`,
},
]}
/>
For most of these properties, you'll want to reference the
[floating-ui docs](https://floating-ui.com/docs/getting-started).
If using `modal={true}` (which is `true` by default), refer to the [PortalProvider
installation](#portalprovider) for more information.
### Popover.Arrow
Popover.Arrow can be used to show an arrow that points at the Trigger element.
In order for the Arrow to show you must have a Trigger element within your
Popover. Arrows extend YStack, see [Stacks](/docs/components/stacks).
### Popover.Trigger
Used to trigger opening of the popover when uncontrolled, just renders a YStack,
see [Stacks](/docs/components/stacks).
### Popover.Content
Extends PopperContent which extends SizableStack which extends a YStack (see
[Stacks](/docs/components/stacks)). Used to display the content of the popover.
### Popover.Anchor
Renders as YStack, see [Stacks](/docs/components/stacks).
When you want the Trigger to be in another location from where the Popover
attaches, use Anchor. When used, Anchor is where the Popover will attach, while
Trigger will open it.
### Sheet (with Adapt)
When used with `Adapt`, you can render a Sheet when that breakpoint is
active. Import `Sheet` directly from `tamagui` or `@tamagui/sheet`.
See [Sheet](/docs/components/sheet) for more props.
Must use `Adapt.Contents` inside the `Sheet.Frame` to insert the
contents given to `Popover.Content`
### Popover.FocusScope
Provides access to the underlying FocusScope component used by Popover for focus
management. Can be used to control focus behavior from a parent component.
void',
description: `Event handler called when auto-focusing on mount. Can be prevented`,
},
{
name: 'onUnmountAutoFocus',
type: '(event: Event) => void',
description: `Event handler called when auto-focusing on unmount. Can be prevented`,
},
]}
/>
### Popover.ScrollView
Must be nested inside Content. Renders as a plain React Native ScrollView. If
used alongside `` and Sheet, Tamagui will automatically know to remove
this ScrollView when swapping into the Sheet, as the Sheet must use its own
ScrollView that handles special logic for interactions with dragging.
## Utility Functions
These functions allow you to programmatically manage open popovers.
```tsx
import {
closeOpenPopovers,
closeLastOpenedPopover,
hasOpenPopovers,
} from '@tamagui/popover'
```
### closeOpenPopovers
Closes all currently open popovers. Returns `true` if any popovers were closed, `false` if none were open.
```tsx
const didClose = closeOpenPopovers()
```
### closeLastOpenedPopover
Closes only the most recently opened popover. Returns `true` if a popover was closed, `false` if none were open.
```tsx
const didClose = closeLastOpenedPopover()
```
### hasOpenPopovers
Returns `true` if there are any open popovers, `false` otherwise.
```tsx
if (hasOpenPopovers()) {
// handle open popovers
}
```
## components/portal/1.0.0
---
title: Portal
description: Send items to other areas of the tree.
name: portal
component: Portal
package: portal
---
Portal is included in `tamagui` as it's used by a few components. For now, it's simply using [@gorhom/portal](https://github.com/gorhom/react-native-portal).
## components/portal/2.0.0
---
title: Portal
description: Send items to other areas of the tree
name: portal
component: Portal
package: portal
---
Portal is included in `tamagui` and is used by [Sheet](/docs/components/sheet),
[Dialog](/docs/components/dialog), [Popover](/docs/components/popover),
[Select](/docs/components/select), and [Toast](/docs/components/toast). See [Z-Index & Stacking](/ui/z-index) for how overlay layering works.
## Native Portal Setup (Recommended)
On web, React's built-in `createPortal` preserves context automatically. On
native, the default portal implementation doesn't preserve React context.
Tamagui automatically re-propagates its own contexts (theme, configuration), but
your custom contexts like navigation or app state won't be available inside
portaled content. The re-propagation also adds some overhead.
We recommend using
[react-native-teleport](https://github.com/kirillzyusko/react-native-teleport)
to solve this. It uses React Native's native portal API to preserve context
automatically.
### Step 1: Install react-native-teleport
```bash
npm install react-native-teleport
```
### Step 2: Import the setup module
In your app's entry file (index.js or App.tsx), before any Tamagui imports:
```tsx
import '@tamagui/native/setup-teleport'
```
That's it! All portal-using components will now preserve context automatically
on native. Without native portals, your custom context from parent components
won't be available inside portaled content:
```tsx
const MyContext = createContext('default')
function App() {
return (
{/* Without native portal: you'd not have context here on native */}
)
}
```
## Alternative Approaches
If you can't use react-native-teleport, there are other ways to handle context
in portals:
### Component Scoping
For Dialog, Popover, and Tooltip, use the `scope` prop to mount a single
instance at your app root. This avoids portals entirely on native:
```tsx
// _layout.tsx - mount once at root with all your providers
{/* label set by trigger */}
{/* rest of your app */}
// anywhere in your app - just the trigger
```
This pattern is also a performance win for lists or tables with many interactive
elements.
### Manual Context Re-propagation
Wrap portal children with the necessary providers:
```tsx
const theme = useTheme()
const myValue = useContext(MyContext)
{/* content that needs context */}
```
This is more verbose and error-prone as you need to remember to re-propagate
every context you use.
## API Reference
### Portal
Enable automatic z-index stacking. Tamagui intelligently stacks z-index both
horizontally (based on mount order) and vertically (nested content is always
above parent but below sibling content that comes after). true{' '}
enables stacking, a number adds to the stacked value, 'global' only
stacks horizontally without nesting logic.
),
},
{
name: 'passThrough',
type: 'boolean',
description: `When true, renders children directly without portal behavior.`,
},
]}
/>
This automatic stacking is already enabled by default in Dialog, Popover, Sheet, and other overlay
components. If you open a Popover from within a Dialog, the Popover will automatically have a
higher z-index than the Dialog without any configuration needed.
## Technical Details
[react-native-teleport](https://github.com/nicksrandall/react-native-teleport)
uses `ReactNativeFabricUIManager.createPortal` (Fabric) or
`UIManager.createPortal` (Paper) to create true native portals that preserve the
React fiber tree.
The default portal implementation, by contrast, uses a JS-based approach with
context providers and a reducer to manage portal state. While compatible with
older RN versions, it breaks React context because it re-renders content in a
separate provider tree.
Tamagui includes a `needsPortalRepropagation()` helper that returns `true` when
using the default portal implementation and `false` when using native portals,
so library authors can conditionally re-propagate context only when needed.
## components/progress/1.0.0
---
title: Progress
description: Display a bar to indicate percent completion.
name: progress
component: Progress
package: progress
demoName: Progress
---
# Progress
Show percent completion with a progress bar
```tsx hero template=Progress
```
Adheres to the{' '}
progressbar role requirements
,
]}
/>
## Installation
Progress is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/progress
```
## Usage
The `value` property controls the percent, but you can override it by adjusting the `x` property.
```tsx
import { Button, Progress } from 'tamagui'
export default () => (
)
```
## API Reference
### Progress
Progress extends [ThemeableStack](/docs/components/stacks#themeablestack), getting [Tamagui standard props](/docs/intro/props), plus:
### Progress.Indicator
`Progress.Indicator` extends [ThemeableStack](/docs/components/stacks#themeablestack), getting [Tamagui standard props](/docs/intro/props).
## components/progress/1.48.0
---
title: Progress
description: Show percent completion with a progress bar.
name: progress
component: Progress
package: progress
demoName: Progress
---
```tsx hero template=Progress
```
Adheres to the{' '}
progressbar role requirements
,
]}
/>
## Installation
Progress is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/progress
```
## Usage
The `value` property controls the percent, but you can override it by adjusting the `x` property.
```tsx
import { Button, Progress } from 'tamagui'
export default () => (
)
```
## API Reference
### Progress
Progress extends [ThemeableStack](/docs/components/stacks#themeablestack), getting [Tamagui standard props](/docs/intro/props), plus:
### Progress.Indicator
`Progress.Indicator` extends [ThemeableStack](/docs/components/stacks#themeablestack), getting [Tamagui standard props](/docs/intro/props).
## components/progress/2.0.0
---
title: Progress
description: Show percent completion with a progress bar
name: progress
component: Progress
package: progress
demoName: Progress
---
```tsx hero template=Progress
```
Adheres to the{' '}
progressbar role requirements
,
]}
/>
## Installation
Progress is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/progress
```
## Usage
The `value` property controls the percent, but you can override it by adjusting the `x` property.
```tsx
import { Button, Progress } from 'tamagui'
export default () => (
)
```
## API Reference
### Progress
Progress extends [ThemeableStack](/docs/components/stacks#themeablestack), getting [Tamagui standard props](/docs/intro/props), plus:
### Progress.Indicator
`Progress.Indicator` extends [ThemeableStack](/docs/components/stacks#themeablestack), getting [Tamagui standard props](/docs/intro/props).
## components/radio-group/1.2.0
---
title: RadioGroup
description: A group of radio buttons
name: radio-group
component: RadioGroup
package: radio-group
demoName: RadioGroup
---
# RadioGroup
Choose one option from a list in a form.StyledUnstyledHeadless
```tsx hero template=RadioGroup
````
```tsx hero template=RadioGroupUnstyled
````
```tsx hero template=RadioGroupHeadless
````
## Installation
RadioGroup is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/radio-group
````
RadioGroup is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/radio-group
```
To use the headless radio group, you want to import it from the
`@tamagui/radio-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.
```bash
npm install @tamagui/radio-headless
```
## Usage
```tsx
import { RadioGroup } from 'tamagui'
export default () => (
)
```
Use the `createRadioGroup` export to create a fully custom RadioGroup 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 `createRadioGroup`.
```tsx template=RadioGroupUnstyled
```
Using the `useRadioGroup` and `useRadioGroupItem` API, you can make your own RadioGroup from scratch.
```tsx template=RadioGroupHeadless
```
## API Reference
### RadioGroup
RadioGroup extend Stack views inheriting all the [Tamagui standard props](/docs/intro/props), plus:
void',
},
{
name: 'accentColor',
type: 'string',
description: 'Sets `accent-color` style when `native` prop is enabled',
},
]}
/>
### RadioGroup.Item
### RadioGroup.Indicator
RadioGroup.Indicator appears only when the parent Item is checked. it extends [ThemeableStack](/docs/components/stacks#themeablestack), getting [Tamagui standard props](/docs/intro/props) adding:
## API Reference
### RadioGroup
RadioGroup extend Stack views inheriting all the [Tamagui standard props](/docs/intro/props), plus:
void',
},
{
name: 'accentColor',
type: 'string',
description: 'Sets `accent-color` style when `native` prop is enabled',
},
]}
/>
### RadioGroup.Item
### RadioGroup.Indicator
RadioGroup.Indicator appears only when the parent Item is checked. it extends [ThemeableStack](/docs/components/stacks#themeablestack), getting [Tamagui standard props](/docs/intro/props) adding:
## components/radio-group/1.3.0
---
title: RadioGroup
description: Use in a form to allow selecting one option from multiple.
name: radio-group
component: RadioGroup
package: radio-group
demoName: RadioGroup
---
```tsx hero template=RadioGroup
```
## Installation
RadioGroup is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/radio-group
```
## Usage
```tsx
import { RadioGroup } from 'tamagui'
export default () => (
)
```
## API Reference
### RadioGroup
RadioGroup extend Stack views inheriting all the [Tamagui standard props](/docs/intro/props), plus:
void',
},
{
name: 'accentColor',
type: 'string',
description: 'Sets `accent-color` style when `native` prop is enabled',
},
]}
/>
### RadioGroup.Item
### RadioGroup.Indicator
RadioGroup.Indicator appears only when the parent Item is checked. it extends [ThemeableStack](/docs/components/stacks#themeablestack), getting [Tamagui standard props](/docs/intro/props) adding:
## components/radio-group/2.0.0
---
title: RadioGroup
description: Use in a form to allow selecting one option from multiple
name: radio-group
component: RadioGroup
package: radio-group
demoName: RadioGroup
---
StyledUnstyledHeadless
```tsx hero template=RadioGroup
````
```tsx hero template=RadioGroup
````
```tsx hero template=RadioGroupHeadless
````
## Installation
RadioGroup is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/radio-group
````
RadioGroup is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/radio-group
```
To use the headless radio group, import from the `@tamagui/radio-headless` package. This package has no dependency on `@tamagui/core` and provides hooks for building custom radio groups with any styling solution.
```bash
npm install @tamagui/radio-headless
```
## Usage
```tsx
import { RadioGroup } from 'tamagui'
export default () => (
)
```
Use the `createRadioGroup` export to create a fully custom radio group that still uses the Tamagui styling system. You provide your own styled components and get back a fully functional radio group component.
```tsx
import { createRadioGroup, RadioGroupContext } from '@tamagui/radio-group'
import { styled, View } from 'tamagui'
const CustomFrame = styled(View, {
// your styles
})
const CustomItem = styled(View, {
context: RadioGroupContext,
// your styles
})
const CustomIndicator = styled(View, {
context: RadioGroupContext,
// your styles
})
export const CustomRadioGroup = createRadioGroup({
Frame: CustomFrame,
Item: CustomItem,
Indicator: CustomIndicator,
})
```
The `@tamagui/radio-headless` package provides three hooks for building custom radio groups:
- `useRadioGroup` - for the container/group
- `useRadioGroupItem` - for individual radio items
- `useRadioGroupItemIndicator` - for the indicator (checked state visual)
### Basic Usage
```tsx
import {
useRadioGroup,
useRadioGroupItem,
useRadioGroupItemIndicator,
RadioGroupContextValue,
RadioGroupItemContextValue,
} from '@tamagui/radio-headless'
import { createContext, useContext } from 'react'
// Create contexts for the group and item
const RadioGroupContext = createContext({})
const RadioGroupItemContext = createContext({
checked: false,
})
function RadioGroup({ children, ...props }) {
const { providerValue, frameAttrs } = useRadioGroup({
orientation: 'vertical',
...props,
})
return (
)
}
// Usage
function App() {
return (
Option 1Option 2Option 3
)
}
```
## API Reference
### RadioGroup
RadioGroup extends Stack views inheriting all the [Tamagui standard props](/docs/intro/props), plus:
When using `createRadioGroup`, you provide styled components:
- `Frame`: The root container component
- `Item`: The radio item component
- `Indicator`: The indicator component
The `useRadioGroup` hook accepts these options:
void',
description: 'Called when the selected value changes.',
},
{
name: 'orientation',
type: '"horizontal" | "vertical"',
description: 'Orientation of the radio group.',
},
{
name: 'accentColor',
type: 'string',
description: 'Sets `accent-color` style when `native` prop is enabled.',
},
]}
/>
### RadioGroup.Item
### RadioGroup.Indicator
RadioGroup.Indicator appears only when the parent Item is checked. It extends [ThemeableStack](/docs/components/stacks#themeablestack), getting [Tamagui standard props](/docs/intro/props) adding:
### useRadioGroup Return Value
| Property | Type | Description |
| ----------------------- | ------------------------ | --------------------------------------------------------------------- |
| `providerValue` | `RadioGroupContextValue` | Value to pass to your context provider |
| `frameAttrs` | `object` | Props to spread on the group container (role, aria-orientation, etc.) |
| `rovingFocusGroupAttrs` | `object` | Props for roving focus behavior (optional) |
### useRadioGroupItem
Hook for individual radio items. Requires a context containing the group state.
```tsx
const {
checked,
isFormControl,
providerValue,
bubbleInput,
native,
frameAttrs,
rovingFocusGroupAttrs,
} = useRadioGroupItem({
radioGroupContext: YourRadioGroupContext,
value: 'option1',
id: 'option1-id',
labelledBy: 'label-id',
disabled: false,
onPress: () => {},
onKeyDown: () => {},
onFocus: () => {},
})
```
| Property | Type | Description |
| --------------- | ----------- | --------------------------------------- |
| `checked` | `boolean` | Whether this item is currently selected |
| `providerValue` | `object` | Context value for the indicator |
| `frameAttrs` | `object` | Props to spread on the item element |
| `bubbleInput` | `ReactNode` | Hidden input for form compatibility |
| `native` | `boolean` | Whether using native radio |
| `isFormControl` | `boolean` | Whether inside a form |
### useRadioGroupItemIndicator
Hook for the visual indicator of checked state.
```tsx
const { checked, ...dataAttrs } = useRadioGroupItemIndicator({
radioGroupItemContext: YourRadioGroupItemContext,
disabled: false,
})
```
| Property | Type | Description |
| --------------- | --------------------- | ---------------------------------- |
| `checked` | `boolean` | Whether the parent item is checked |
| `data-state` | `string` | 'checked' or 'unchecked' |
| `data-disabled` | `string \| undefined` | Present when disabled |
## components/roving-focus/2.0.0
---
title: RovingFocusGroup
description: Manage keyboard navigation within a group of focusable elements.
name: roving-focus
component: RovingFocusGroup
package: roving-focus
---
A utility component for managing keyboard focus within a group of elements using the
roving tabindex pattern. Enables arrow key navigation between focusable items while
maintaining a single tab stop for the group.
Note that this is primarily a web component. On native it renders children without keyboard navigation management.
## Installation
RovingFocusGroup is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/roving-focus
```
## Usage
Wrap focusable items with RovingFocusGroup and use RovingFocusGroup.Item for each focusable element:
```tsx
import { Button, RovingFocusGroup, XStack } from 'tamagui'
export default () => (
FirstSecondThird
)
```
## How It Works
The roving tabindex pattern allows a group of focusable elements to act as a single tab stop. When the user tabs into the group, focus moves to the currently active item. Arrow keys then navigate between items within the group.
This improves keyboard navigation by:
- Reducing the number of tab stops on a page
- Providing intuitive arrow key navigation within related controls
- Maintaining focus state across the group
## Orientation
Set `orientation` to control which arrow keys navigate:
```tsx
import { Button, RovingFocusGroup, YStack } from 'tamagui'
export default () => (
// Up/Down arrows navigate, Left/Right are ignored
Option 1Option 2Option 3
)
```
## Looping Navigation
Enable `loop` to wrap focus from the last item back to the first:
```tsx
import { Button, RovingFocusGroup, XStack } from 'tamagui'
export default () => (
FirstMiddleLast
{/* Arrow right from "Last" goes to "First" */}
)
```
## Controlled Tab Stop
Control which item is the current tab stop:
```tsx
import { Button, RovingFocusGroup, XStack } from 'tamagui'
import { useState } from 'react'
export default () => {
const [currentId, setCurrentId] = useState('item-2')
return (
FirstSecond (default)Third
)
}
```
## Non-Focusable Items
Mark items as non-focusable to skip them during keyboard navigation:
```tsx
import { Button, RovingFocusGroup, XStack } from 'tamagui'
export default () => (
EnabledDisabledEnabled
)
```
## Entry Focus Control
Handle focus when the group first receives focus:
```tsx
import { Button, RovingFocusGroup, XStack } from 'tamagui'
export default () => (
{
// Prevent default focus behavior
// event.preventDefault()
console.log('Group received focus')
}}
>
FirstSecond
)
```
## API Reference
### RovingFocusGroup
void',
description: 'Callback when the current tab stop changes.',
},
{
name: 'onEntryFocus',
type: '(event: Event) => void',
description:
'Callback when focus enters the group via keyboard. Call event.preventDefault() to prevent default focus behavior.',
},
{
name: 'asChild',
type: 'boolean',
default: 'false',
description: 'When true, renders as a Slot, merging props onto the child element.',
},
]}
/>
### RovingFocusGroup.Item
## Keyboard Navigation
| Key | Action |
| ------------------- | ------------------------------------------------- |
| `Tab` | Move focus into/out of the group |
| `Arrow Left/Right` | Move focus between items (horizontal orientation) |
| `Arrow Up/Down` | Move focus between items (vertical orientation) |
| `Home` / `Page Up` | Move focus to first item |
| `End` / `Page Down` | Move focus to last item |
## Usage in Components
RovingFocusGroup is used internally by several Tamagui components to provide keyboard navigation:
- [Tabs](/docs/components/tabs) - Navigate between tab triggers
- [RadioGroup](/docs/components/radio-group) - Navigate between radio options
- [ToggleGroup](/docs/components/toggle-group) - Navigate between toggle options
RovingFocusGroup is primarily designed for web platforms. On React Native, it renders
children without keyboard navigation management since native platforms handle focus
differently.
## components/scroll-view/1.0.0
---
title: ScrollView
description: React Native ScrollView with Tamagui props.
name: scrollView
component: ScrollView
package: scroll-view
demoName: ScrollView
---
```tsx hero template=ScrollView
```
## Installation
ScrollView is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/scroll-view
```
## Usage
```tsx
import { ScrollView, YStack, ListItem } from 'tamagui'
export default () => (
1234
)
```
## API Reference
### ScrollView
See [React Native ScrollView](https://reactnative.dev/docs/scrollview) and [Tamagui style props](https://tamagui.dev/docs/intro/props).
## components/scroll-view/2.0.0
---
title: ScrollView
description: React Native ScrollView with Tamagui props
name: scrollView
component: ScrollView
package: scroll-view
demoName: ScrollView
---
```tsx hero template=ScrollView
```
## Installation
ScrollView is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/scroll-view
```
## Usage
```tsx
import { ScrollView, YStack, ListItem } from 'tamagui'
export default () => (
1234
)
```
## API Reference
### ScrollView
See [React Native ScrollView](https://reactnative.dev/docs/scrollview) and [Tamagui style props](https://tamagui.dev/docs/intro/props).
## components/select/1.0.0
---
title: Select
description: A simple select component
name: select
component: Select
package: select
demoName: Select
---
# Select
Show a menu of items users can select from one of.
```tsx hero template=Select
```
### Anatomy
```tsx
import { Select } from 'tamagui' // or '@tamagui/select'
export default () => (
)
```
Note that Select only works on Native using the Adapt component to adapt it to a Sheet.
See below for docs.
### API
#### <Select />
Contains every component for the select:
void',
description: `Callback on value change`,
},
{
name: 'open',
type: 'boolean',
description: `Controlled open value`,
},
{
name: 'defaultOpen',
type: 'boolean',
description: `Default open value`,
},
{
name: 'onOpenChange',
type: '(open: boolean) => void',
description: `Callback on open change`,
},
{
name: 'dir',
type: 'Direction',
description: `Direction of text display`,
},
{
name: 'name',
type: 'string',
description: `For use in forms`,
},
]}
/>
#### <Trigger />
Extends [ListItem](/docs/components/list-item) to give sizing, icons, and more.
#### <Value />
Extends [Paragraph](/docs/components/text), adding:
#### <Content />
Main container for Select content, used to contain the up/down arrows, no API beyond children.
#### <ScrollUpButton />
Inside Content first, displays when you can scroll up, stuck to the top.
Extends [YStack](/docs/components/stacks).
#### <ScrollDownButton />
Inside Content last, displays when you can scroll down, stuck to the bottom.
Extends [YStack](/docs/components/stacks).
#### <Viewport />
Extends [ThemeableStack](/docs/components/stacks#themeablestack). Contains scrollable content items as children.
#### <Group />
Extends [YStack](/docs/components/stacks). Use only when grouping together items, alongside a Label as the first child.
#### <Label />
Extends [ListItem](/docs/components/list-item). Used to label Groups.
#### <Item />
Extends [ListItem](/docs/components/list-item). Used to add selectable values ot the list. Must provide an index as React Native doesn't give any escape hatch for us to configure that automatically.
#### <ItemText />
Extends [Paragraph](/docs/components/text). Used inside Item to provide unselectable text that will show above once selected in the parent Select.
#### <Sheet />
When used alongside ``, Select will render as a sheet when that breakpoint is active.
This is the only way to render a Select on Native for now, as mobile apps tend to show Select very differently from web and Tamagui wants to present the right abstractions for each platform.
See [Sheet](/docs/components/sheet) for more props.
Must use `Select.SheetContents` inside the `Select.Sheet.Frame` to insert the contents given to `Select.Content`
```tsx
import { Select } from 'tamagui' // or '@tamagui/select'
export default () => (
)
```
## components/select/1.128.0
---
title: Select
description: Show a menu of items that users can select from.
name: select
component: Select
package: select
demoName: Select
---
```tsx hero template=Select
```
## Installation
Select is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/select
```
## Anatomy
```tsx
import { Select } from 'tamagui' // or '@tamagui/select'
export default () => (
)
```
Note that Select only works on Native using the Adapt component to adapt it to a Sheet.
See below for docs.
## API Reference
### Select
Contains every component for the select:
void',
description: `Callback on value change`,
},
{
name: 'open',
type: 'boolean',
description: `Controlled open value`,
},
{
name: 'defaultOpen',
type: 'boolean',
description: `Default open value`,
},
{
name: 'onOpenChange',
type: '(open: boolean) => void',
description: `Callback on open change`,
},
{
name: 'dir',
type: 'Direction',
description: `Direction of text display`,
},
{
name: 'name',
type: 'string',
description: `For use in forms`,
},
{
name: 'native',
type: 'NativeValue',
description: `If passed, will render a native component instead of the custom one. Currently only \`web\` is supported.`,
},
]}
/>
### Select.Trigger
Extends [ListItem](/docs/components/list-item) to give sizing, icons, and more.
#### Select.Value
Extends [Paragraph](/docs/components/text), adding:
#### SelectContent
Main container for Select content, used to contain the up/down arrows, no API beyond children.
#### Select.ScrollUpButton
Inside Content first, displays when you can scroll up, stuck to the top.
Extends [YStack](/docs/components/stacks).
### Select.ScrollDownButton
Inside Content last, displays when you can scroll down, stuck to the bottom.
Extends [YStack](/docs/components/stacks).
### Select.Viewport
Extends [ThemeableStack](/docs/components/stacks#themeablestack). Contains scrollable content items as children.
Make sure to not pass `height` prop as that is managed internally because of UX reasons
and having a fixed height will break that behavior
### Select.Group
Extends [YStack](/docs/components/stacks). Use only when grouping together items, alongside a Label as the first child.
### Select.Label
Extends [ListItem](/docs/components/list-item). Used to label Groups.
### Select.Item
Extends [ListItem](/docs/components/list-item). Used to add selectable values to the list. Must provide an index as React Native doesn't give any escape hatch for us to configure that automatically.
### Select.ItemText
Extends [Paragraph](/docs/components/text). Used inside Item to provide unselectable text that will show above once selected in the parent Select.
### Select.FocusScope
Provides access to the underlying FocusScope component used by Select for focus management. Can be used to control focus behavior from a parent component.
void',
description: `Event handler called when auto-focusing on mount. Can be prevented`,
},
{
name: 'onUnmountAutoFocus',
type: '(event: Event) => void',
description: `Event handler called when auto-focusing on unmount. Can be prevented`,
},
]}
/>
### Select.Sheet
When used alongside ``, Select will render as a sheet when that breakpoint is active.
This is the only way to render a Select on Native for now, as mobile apps tend to show Select very differently from web and Tamagui wants to present the right abstractions for each platform.
See [Sheet](/docs/components/sheet) for more props.
Must use `Select.Adapt.Contents` inside the `Select.Sheet.Frame` to insert the contents given to `Select.Content`
```tsx
import { Select } from 'tamagui' // or '@tamagui/select'
export default () => (
)
```
## components/select/1.141.0
---
title: Select
description: Show a menu of items that users can select from.
name: select
component: Select
package: select
demoName: Select
---
```tsx hero template=Select
```
## Installation
Select is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/select
```
## Anatomy
```tsx
import { Select } from 'tamagui' // or '@tamagui/select'
export default () => (
)
```
Note that Select only works on Native using the Adapt component to adapt it to a Sheet.
See below for docs.
## Server-Side Rendering (SSR)
By default, Select uses a portal-based mechanism to display the selected item's text in the trigger. This happens in a client-side effect, which can cause hydration mismatches when using SSR.
To fix this, use the `renderValue` prop to provide the label synchronously during render:
```tsx
const items = [
{ value: 'apple', label: 'Apple' },
{ value: 'orange', label: 'Orange' },
]
// Create a lookup function
const getLabel = (value: string) => items.find((item) => item.value === value)?.label
export function MySelect() {
const [value, setValue] = React.useState('apple')
return (
)
}
```
When `renderValue` is provided, it's called synchronously during render, ensuring the server and client render the same content.
## API Reference
### Select
Contains every component for the select:
void',
description: `Callback on value change`,
},
{
name: 'open',
type: 'boolean',
description: `Controlled open value`,
},
{
name: 'defaultOpen',
type: 'boolean',
description: `Default open value`,
},
{
name: 'onOpenChange',
type: '(open: boolean) => void',
description: `Callback on open change`,
},
{
name: 'dir',
type: 'Direction',
description: `Direction of text display`,
},
{
name: 'name',
type: 'string',
description: `For use in forms`,
},
{
name: 'native',
type: 'NativeValue',
description: `If passed, will render a native component instead of the custom one. Currently only \`web\` is supported.`,
},
{
name: 'renderValue',
type: '(value: string) => React.ReactNode',
description: `Render function for the selected value. Use this for SSR support to avoid hydration mismatches. When provided, this is called synchronously during render to display the selected value.`,
},
]}
/>
### Select.Trigger
Extends [ListItem](/docs/components/list-item) to give sizing, icons, and more.
#### Select.Value
Extends [Paragraph](/docs/components/text), adding:
#### SelectContent
Main container for Select content, used to contain the up/down arrows, no API beyond children.
#### Select.ScrollUpButton
Inside Content first, displays when you can scroll up, stuck to the top.
Extends [YStack](/docs/components/stacks).
### Select.ScrollDownButton
Inside Content last, displays when you can scroll down, stuck to the bottom.
Extends [YStack](/docs/components/stacks).
### Select.Viewport
Extends [ThemeableStack](/docs/components/stacks#themeablestack). Contains scrollable content items as children.
Make sure to not pass `height` prop as that is managed internally because of UX reasons
and having a fixed height will break that behavior
### Select.Group
Extends [YStack](/docs/components/stacks). Use only when grouping together items, alongside a Label as the first child.
### Select.Label
Extends [ListItem](/docs/components/list-item). Used to label Groups.
### Select.Item
Extends [ListItem](/docs/components/list-item). Used to add selectable values to the list. Must provide an index as React Native doesn't give any escape hatch for us to configure that automatically.
### Select.ItemText
Extends [Paragraph](/docs/components/text). Used inside Item to provide unselectable text that will show above once selected in the parent Select.
### Select.FocusScope
Provides access to the underlying FocusScope component used by Select for focus management. Can be used to control focus behavior from a parent component.
void',
description: `Event handler called when auto-focusing on mount. Can be prevented`,
},
{
name: 'onUnmountAutoFocus',
type: '(event: Event) => void',
description: `Event handler called when auto-focusing on unmount. Can be prevented`,
},
]}
/>
### Select.Sheet
When used alongside ``, Select will render as a sheet when that breakpoint is active.
This is the only way to render a Select on Native for now, as mobile apps tend to show Select very differently from web and Tamagui wants to present the right abstractions for each platform.
See [Sheet](/docs/components/sheet) for more props.
Must use `Select.Adapt.Contents` inside the `Select.Sheet.Frame` to insert the contents given to `Select.Content`
```tsx
import { Select } from 'tamagui' // or '@tamagui/select'
export default () => (
)
```
## components/select/1.19.0
---
title: Select
description: A simple select component
name: select
component: Select
package: select
demoName: Select
---
# Select
Show a menu of items users can select from one of
```tsx hero template=Select
```
## Anatomy
```tsx
import { Select } from 'tamagui' // or '@tamagui/select'
export default () => (
)
```
Note that Select only works on Native using the Adapt component to adapt it to a Sheet.
See below for docs.
## API Reference
### Select
Contains every component for the select:
void',
description: `Callback on value change`,
},
{
name: 'open',
type: 'boolean',
description: `Controlled open value`,
},
{
name: 'defaultOpen',
type: 'boolean',
description: `Default open value`,
},
{
name: 'onOpenChange',
type: '(open: boolean) => void',
description: `Callback on open change`,
},
{
name: 'dir',
type: 'Direction',
description: `Direction of text display`,
},
{
name: 'name',
type: 'string',
description: `For use in forms`,
},
{
name: 'native',
type: 'NativeValue',
description: `If passed, will render a native component instead of the custom one. Currently only \`web\` is supported.`,
},
]}
/>
### Select.Trigger
Extends [ListItem](/docs/components/list-item) to give sizing, icons, and more.
#### Select.Value
Extends [Paragraph](/docs/components/text), adding:
#### SelectContent
Main container for Select content, used to contain the up/down arrows, no API beyond children.
#### Select.ScrollUpButton
Inside Content first, displays when you can scroll up, stuck to the top.
Extends [YStack](/docs/components/stacks).
### Select.ScrollDownButton
Inside Content last, displays when you can scroll down, stuck to the bottom.
Extends [YStack](/docs/components/stacks).
### Select.Viewport
Extends [ThemeableStack](/docs/components/stacks#themeablestack). Contains scrollable content items as children.
### Select.Group
Extends [YStack](/docs/components/stacks). Use only when grouping together items, alongside a Label as the first child.
### Select.Label
Extends [ListItem](/docs/components/list-item). Used to label Groups.
### Select.Item
Extends [ListItem](/docs/components/list-item). Used to add selectable values ot the list. Must provide an index as React Native doesn't give any escape hatch for us to configure that automatically.
### Select.ItemText
Extends [Paragraph](/docs/components/text). Used inside Item to provide unselectable text that will show above once selected in the parent Select.
### Select.Sheet
When used alongside ``, Select will render as a sheet when that breakpoint is active.
This is the only way to render a Select on Native for now, as mobile apps tend to show Select very differently from web and Tamagui wants to present the right abstractions for each platform.
See [Sheet](/docs/components/sheet) for more props.
Must use `Select.SheetContents` inside the `Select.Sheet.Frame` to insert the contents given to `Select.Content`
```tsx
import { Select } from 'tamagui' // or '@tamagui/select'
export default () => (
)
```
## components/select/1.40.0
---
title: Select
description: Show a menu of items that users can select from.
name: select
component: Select
package: select
demoName: Select
---
```tsx hero template=Select
```
## Installation
Select is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/select
```
## Anatomy
```tsx
import { Select } from 'tamagui' // or '@tamagui/select'
export default () => (
)
```
Note that Select only works on Native using the Adapt component to adapt it to a Sheet.
See below for docs.
## API Reference
### Select
Contains every component for the select:
void',
description: `Callback on value change`,
},
{
name: 'open',
type: 'boolean',
description: `Controlled open value`,
},
{
name: 'defaultOpen',
type: 'boolean',
description: `Default open value`,
},
{
name: 'onOpenChange',
type: '(open: boolean) => void',
description: `Callback on open change`,
},
{
name: 'dir',
type: 'Direction',
description: `Direction of text display`,
},
{
name: 'name',
type: 'string',
description: `For use in forms`,
},
{
name: 'native',
type: 'NativeValue',
description: `If passed, will render a native component instead of the custom one. Currently only \`web\` is supported.`,
},
]}
/>
### Select.Trigger
Extends [ListItem](/docs/components/list-item) to give sizing, icons, and more.
#### Select.Value
Extends [Paragraph](/docs/components/text), adding:
#### SelectContent
Main container for Select content, used to contain the up/down arrows, no API beyond children.
#### Select.ScrollUpButton
Inside Content first, displays when you can scroll up, stuck to the top.
Extends [YStack](/docs/components/stacks).
### Select.ScrollDownButton
Inside Content last, displays when you can scroll down, stuck to the bottom.
Extends [YStack](/docs/components/stacks).
### Select.Viewport
Extends [ThemeableStack](/docs/components/stacks#themeablestack). Contains scrollable content items as children.
Make sure to not pass `height` prop as that is managed internally because of UX reasons
and having a fixed height will break that behavior
### Select.Group
Extends [YStack](/docs/components/stacks). Use only when grouping together items, alongside a Label as the first child.
### Select.Label
Extends [ListItem](/docs/components/list-item). Used to label Groups.
### Select.Item
Extends [ListItem](/docs/components/list-item). Used to add selectable values ot the list. Must provide an index as React Native doesn't give any escape hatch for us to configure that automatically.
### Select.ItemText
Extends [Paragraph](/docs/components/text). Used inside Item to provide unselectable text that will show above once selected in the parent Select.
### Select.Sheet
When used alongside ``, Select will render as a sheet when that breakpoint is active.
This is the only way to render a Select on Native for now, as mobile apps tend to show Select very differently from web and Tamagui wants to present the right abstractions for each platform.
See [Sheet](/docs/components/sheet) for more props.
Must use `Select.Adapt.Contents` inside the `Select.Sheet.Frame` to insert the contents given to `Select.Content`
```tsx
import { Select } from 'tamagui' // or '@tamagui/select'
export default () => (
)
```
## components/select/2.0.0
---
title: Select
description: Show a menu of items that users can select from
name: select
component: Select
package: select
demoName: Select
---
```tsx hero template=Select
```
Select provides a dropdown menu for choosing from a list of options. It's fully accessible with keyboard navigation, supports typeahead search, and [automatically stacks](/ui/z-index) above other content.
## Installation
Select is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/select
```
For native apps, we recommend [setting up native
portals](/docs/components/portal#native-portal-setup-recommended) to preserve React
context inside Select content.
## Anatomy
```tsx
import { Select } from 'tamagui' // or '@tamagui/select'
export default () => (
)
```
Note that Select only works on Native using the Adapt component to adapt it to a Sheet.
See below for docs.
## API Reference
### Select
Contains every component for the select:
void',
description: `Callback on value change.`,
},
{
name: 'open',
type: 'boolean',
description: `Controlled open value.`,
},
{
name: 'defaultOpen',
type: 'boolean',
description: `Default open value.`,
},
{
name: 'onOpenChange',
type: '(open: boolean) => void',
description: `Callback on open change.`,
},
{
name: 'dir',
type: 'Direction',
description: `Direction of text display.`,
},
{
name: 'name',
type: 'string',
description: `For use in forms.`,
},
{
name: 'native',
type: 'NativeValue',
description: `If passed, will render a native component instead of the custom one. Currently only \`web\` is supported.`,
},
{
name: 'renderValue',
type: '(value: string) => ReactNode',
description: `Render function for the selected value. Useful for SSR when you need custom display text. By default, Select falls back to showing the raw value for SSR compatibility.`,
},
{
name: 'lazyMount',
type: 'boolean',
default: 'false',
description: `When true, defers mounting Select items until opened using React's startTransition. Significantly improves initial render performance for pages with many Selects. Should be combined with \`renderValue\` for best results.`,
},
{
name: 'zIndex',
type: 'number',
description: `z-index for the select portal. Use when select dropdowns need to appear above other portaled content like dialogs or fixed headers. Defaults to automatic stacking (~100000).`,
},
]}
/>
### Select.Trigger
Extends [ListItem](/docs/components/list-item) to give sizing, icons, and more.
### Select.Value
Extends [Paragraph](/docs/components/text), adding:
### Select.Content
Main container for Select content, used to contain the up/down arrows, no API beyond children.
### Select.ScrollUpButton
Inside Content first, displays when you can scroll up, stuck to the top.
Extends [YStack](/docs/components/stacks).
### Select.ScrollDownButton
Inside Content last, displays when you can scroll down, stuck to the bottom.
Extends [YStack](/docs/components/stacks).
### Select.Viewport
Extends [ThemeableStack](/docs/components/stacks#themeablestack). Contains scrollable content items as children.
Make sure to not pass `height` prop as that is managed internally because of UX reasons
and having a fixed height will break that behavior.
### Select.Group
Extends [YStack](/docs/components/stacks). Use only when grouping together items, alongside a Label as the first child.
### Select.Label
Extends [SizableText](/docs/components/text). Used to label Groups. Includes size-based padding and minHeight for consistent appearance with other Select items.
### Select.Item
Extends [ListItem](/docs/components/list-item). Used to add selectable values to the list. Must provide an index as React Native doesn't give any escape hatch for us to configure that automatically.
### Select.ItemText
Extends [Paragraph](/docs/components/text). Used inside Item to provide unselectable text that will show above once selected in the parent Select.
### Select.Indicator
An animated indicator that highlights the currently focused item. Place it inside `Select.Viewport` to enable a smooth sliding highlight animation as users navigate through options.
```tsx
{/* items */}
```
Use the `transition` prop to control the animation speed. You can use any animation name from your config like `quick`, `quicker`, or `quickest`.
By default, Select uses the item's `hoverStyle` and `pressStyle` for hover feedback. Add
`Select.Indicator` for a smoother animated effect. If using the indicator, you may want
to set items to have transparent hover styles to avoid visual conflict.
### Select.FocusScope
Provides access to the underlying FocusScope component used by Select for focus management. Can be used to control focus behavior from a parent component.
void',
description: `Event handler called when auto-focusing on mount. Can be prevented.`,
},
{
name: 'onUnmountAutoFocus',
type: '(event: Event) => void',
description: `Event handler called when auto-focusing on unmount. Can be prevented.`,
},
]}
/>
## Performance
For pages with many Select components, you can significantly improve initial render performance by using the `lazyMount` prop combined with `renderValue`:
```tsx
const labels = {
apple: 'Apple',
orange: 'Orange',
banana: 'Banana',
}
```
**How it works:**
- `lazyMount` defers mounting all Select items until the dropdown is first opened
- The mount happens inside React's `startTransition`, keeping the trigger responsive
- `renderValue` provides the display text synchronously, avoiding the need to mount items just to show the selected value
- Once mounted, items stay mounted for fast subsequent opens
This is especially useful when rendering many Selects on a single page, as each Select with 20+ items would otherwise mount all those items on initial page load.
### Select.Sheet
When used alongside ``, Select will render as a sheet when that breakpoint is active.
This is the only way to render a Select on Native for now, as mobile apps tend to show Select very differently from web and Tamagui wants to present the right abstractions for each platform.
See [Sheet](/docs/components/sheet) for more props.
Must use `Select.Adapt.Contents` inside the `Select.Sheet.Frame` to insert the contents given to `Select.Content`
```tsx
import { Select } from 'tamagui' // or '@tamagui/select'
export default () => (
)
```
## components/separator/1.0.0
---
title: Separator
description: Create borders between components.
name: separator
component: Separator
package: separator
demoName: Separator
---
```tsx hero template=Separator
```
## Installation
Separator is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/separator
```
## Usage
Separator uses the `borderWidth` and `borderColor` attribute for its style, so be sure to override those when extending it.
```tsx
export default () => (
BlogDocsSource
)
```
## API Reference
### Separator props
Separators extend Stack views inheriting all the [Tamagui standard props](/docs/intro/props), plus:
## components/separator/2.0.0
---
title: Separator
description: Create borders between components
name: separator
component: Separator
package: separator
demoName: Separator
---
```tsx hero template=Separator
```
## Installation
Separator is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/separator
```
## Usage
Separator uses the `borderWidth` and `borderColor` attribute for its style, so be sure to override those when extending it.
```tsx
export default () => (
BlogDocsSource
)
```
## API Reference
### Separator
Separator extends Stack views inheriting all the [Tamagui standard props](/docs/intro/props), plus:
## components/shapes/1.0.0
---
title: Shapes
description: Easy to use Square and Circle.
name: shapes
component: Square
package: shapes
demoName: Shapes
---
```tsx hero template=Shapes
```
## Installation
Shapes is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/shapes
```
## Usage
Tamagui supports sizing shapes using your `size` tokens, or plain numbers.
```tsx
import { Circle, Square } from 'tamagui'
export default () => (
<>
>
)
```
## API Reference
### Square
`Square` extends Stack views inheriting all the [Tamagui standard props](/docs/intro/props), plus:
### Circle
`Circle` extends [Square](#square), setting `circular` to `true`.
## components/shapes/2.0.0
---
title: Shapes
description: Easy to use Square and Circle
name: shapes
component: Square
package: shapes
demoName: Shapes
---
```tsx hero template=Shapes
```
## Installation
Shapes is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/shapes
```
## Usage
Tamagui supports sizing shapes using your `size` tokens, or plain numbers.
```tsx
import { Circle, Square } from 'tamagui'
export default () => (
<>
>
)
```
## API Reference
### Square
Square extends Stack views inheriting all the [Tamagui standard props](/docs/intro/props), plus:
### Circle
Circle extends [Square](#square), setting `circular` to `true`.
## components/sheet/1.0.0
---
title: Sheet
description: A simple sheet component
name: sheet
component: Sheet
package: sheet
demoName: Sheet
---
# Sheet
A bottom sheet that slides up.
```tsx hero template=Sheet
```
### Anatomy
```tsx
import { Sheet } from 'tamagui' // or '@tamagui/sheet'
export default () => (
{/* ...inner contents */}
)
```
### API
#### <Sheet />
Contains every component for the sheet.
void',
description: `Called on change open, controlled or uncontrolled.`,
},
{
name: 'position',
type: 'number',
description: `Controlled position, set to an index of snapPoints.`,
},
{
name: 'defaultPosition',
type: 'number',
description: `Uncontrolled default position on mount.`,
},
{
name: 'snapPoints',
type: 'number[]',
default: `[80, 10]`,
description: `Array of numbers, 0-100 that corresponds to % of the screen it should take up. Should go from most visible to least visible in order. Use "open" prop for fully closed.`,
},
{
name: 'onPositionChange',
type: '(position: number) => void',
description: `Called on change position, controlled or uncontrolled.`,
},
{
name: 'dismissOnOverlayPress',
type: 'boolean',
default: 'true',
description: `Controls tapping on the overlay to close, defaults to true.`,
},
{
name: 'animationConfig',
type: 'Animated.SpringAnimationConfig',
default: 'true',
description: `Customize the spring used, passed to react-native Animated.spring().`,
},
{
name: 'disableDrag',
type: 'boolean',
description: `Disables all touch events to drag the sheet.`,
},
{
name: 'modal',
type: 'boolean',
description: `Renders sheet into the root of your app instead of inline.`,
},
{
name: 'dismissOnSnapToBottom',
type: 'boolean',
description: `Adds a snap point to the end of your snap points set to "0", that when snapped to will set open to false (uncontrolled) and call onOpenChange with false (controlled).`,
},
{
name: 'forceRemoveScrollEnabled',
type: 'boolean',
default: 'false',
description: `By default. Tamagui uses react-remove-scroll to prevent anything outside the sheet scrolling. This can cause some issues so you can override the behavior with this prop (either true or false).`,
},
{
name: 'portalProps',
type: 'Object',
description: `YStack props that can be passed to the Portal that sheet uses when in modal mode.`,
},
]}
/>
#### <Overlay />
Displays behind Frame. Extends [YStack](/docs/components/stacks).
#### <Frame />
Contains the content. Extends [YStack](/docs/components/stacks).
#### <Handle />
Shows a handle above the frame by default, on tap it will cycle between `snapPoints` but this can be overridden with `onPress`.
Extends [XStack](/docs/components/stacks).
#### <Scrollview />
Allows scrolling within Sheet. Extends [Scrollview](/docs/components/scroll-view).
### Notes
For Android you need to manually re-propagate any context when using `modal`. This is because React Native doesn't support portals yet.
## components/sheet/1.116.0
---
title: Sheet
description: A simple sheet component
name: sheet
component: Sheet
package: sheet
demoName: Sheet
---
# Sheet
A bottom sheet that slides up
```tsx hero template=Sheet
```
## Installation
Sheet is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/sheet
```
### PortalProvider
When rendering into root of app instead of inline, you'll first need to install the `@tamagui/portal` package:
```bash
npm install @tamagui/portal
```
Then add `PortalProvider` to the root of your app:
```tsx fileName="App.tsx"
import { PortalProvider } from '@tamagui/portal'
import YourApp from './components/YourApp'
function App() {
return (
)
}
export default App
```
## Anatomy
```tsx
import { Sheet } from 'tamagui' // or '@tamagui/sheet'
export default () => (
{/* ...inner contents */}
)
```
## Snap points
By default, snap points are treated as percentages.
```tsx
// 85% and 50%
```
The behavior of snap points can be changed by setting the `snapPointsMode` prop to any of these values:
- **percent** (default) - Snap points are percentages of the parent container or screen as numbers
- **constant** - Snap points are raw pixel values as numbers
- **fit** - The sheet is constrained to the content's natural height without the `snapPoints` prop
- **mixed** - Snap points can be either numbers (pixels), percentages as strings (ex: `"50%"`), or `"fit"` for fit behavior
Snap points should be ordered from largest to smallest (most visible to least visible). When using `mixed` mode with the `"fit"` as a snap point, it must be the first and largest snap point.
## Unstyled
Adding the `unstyled` prop to your Handle, Overlay or Frame will turn off the default styles allowing you to customize without having to override any of the built-in styling.
## Headless with `createSheet`
Using the `createSheet` export, you can create a fully custom sheet without using any of the default styles. This is similar to `unstyled`, but it lets you also control the `open` variant.
Here's an example:
```tsx
import { Stack, styled } from '@tamagui/core'
import { createSheet } from '@tamagui/sheet'
const Handle = styled(Stack, {
variants: {
open: {
true: {
opacity: 0.35,
},
false: {
opacity: 0.5,
},
},
} as const,
})
const Overlay = styled(Stack, {
variants: {
open: {
true: {
opacity: 1,
pointerEvents: 'auto',
},
false: {
opacity: 0,
pointerEvents: 'none',
},
},
} as const,
})
const Frame = styled(Stack, {
backgroundColor: '$background',
// can add open variant as well
})
export const Sheet = createSheet({
Frame,
Handle,
Overlay,
})
```
## Native support
Sheets now support rendering to a native iOS sheet, while still rendering any of your React Native content inside of them.
Because Metro doesn't support conditional imports and we don't want to make `tamagui` enforce installing native dependencies in order to get started, there's an install step.
As of the time of writing, we are using the new `3.0.x` branch which is in beta. Until ready, it does require a bit more setup.
```sh
yarn add react-native-ios-modal@3.0.0-5 react-native-ios-utilities@next @dominicstop/ts-event-emitter
```
Then, rebuild your native iOS app so it picks up the new native dependencies. This is done either through Expo or plain React Native.
Finally, set it up:
```tsx
import { Sheet, setupNativeSheet } from '@tamagui/sheet'
import * as NativeModal from 'react-native-ios-modal'
setupNativeSheet('ios', NativeModal)
// now you can use the `native` prop:
export default {/* ... the rest of your sheet */}
```
## API Reference
### Sheet
Contains every component for the sheet.
void',
description: `Called on change open, controlled or uncontrolled.`,
},
{
name: 'position',
type: 'number',
description: `Controlled position, set to an index of snapPoints.`,
},
{
name: 'defaultPosition',
type: 'number',
description: `Uncontrolled default position on mount.`,
},
{
name: 'snapPoints',
type: '(number | string)[] | undefined',
default: `[80]`,
description: `Array of values representing different sizes for the sheet to snap to. Not used in 'fit' mode. See docs above for usage information.`,
},
{
name: 'snapPointsMode',
type: '"percent" | "constant" | "fit" | "mixed"',
default: '"percent"',
description: `Alters the behavior of the 'snapPoints' prop. See docs above for usage information.`,
},
{
name: 'onPositionChange',
type: '(position: number) => void',
description: `Called on change position, controlled or uncontrolled.`,
},
{
name: 'dismissOnOverlayPress',
type: 'boolean',
default: 'true',
description: `Controls tapping on the overlay to close, defaults to true.`,
},
{
name: 'animationConfig',
type: 'Animated.SpringAnimationConfig',
default: 'true',
description: `Customize the spring used, passed to react-native Animated.spring().`,
},
{
name: 'native',
type: 'boolean | "ios"[]',
description: `(iOS only) Render to a native sheet, must install native dependency first.`,
},
{
name: 'disableDrag',
type: 'boolean',
description: `Disables all touch events to drag the sheet.`,
},
{
name: 'modal',
type: 'boolean',
description: `Renders sheet into the root of your app instead of inline.`,
},
{
name: 'dismissOnSnapToBottom',
type: 'boolean',
description: `Adds a snap point to the end of your snap points set to "0", that when snapped to will set open to false (uncontrolled) and call onOpenChange with false (controlled).`,
},
{
name: 'forceRemoveScrollEnabled',
type: 'boolean',
default: 'false',
description: `By default. Tamagui uses react-remove-scroll to prevent anything outside the sheet scrolling. This can cause some issues so you can override the behavior with this prop (either true or false).`,
},
{
name: 'portalProps',
type: 'Object',
description: `YStack props that can be passed to the Portal that sheet uses when in modal mode.`,
},
{
name: 'moveOnKeyboardChange',
type: 'boolean',
default: 'false',
description:
'Native-only flag that will make the sheet move up when the mobile keyboard opens so the focused input remains visible.',
},
{
name: 'unmountChildrenWhenHidden',
type: 'boolean',
default: 'false',
description:
'Flag to enable unmounting the children after the exit animation has completed.',
},
]}
/>
If using `modal={true}` (which is `true` by default), refer to the [PortalProvider
installation](/ui/sheet/1.59.0#portalprovider) for more information.
### Sheet.Overlay
Displays behind Frame. Extends [YStack](/docs/components/stacks).
### Sheet.Frame
Contains the content. Extends [YStack](/docs/components/stacks).
### Sheet.Handle
Shows a handle above the frame by default, on tap it will cycle between `snapPoints` but this can be overridden with `onPress`.
Extends [XStack](/docs/components/stacks).
### Sheet.ScrollView
Allows scrolling within Sheet. Extends [ScrollView](/docs/components/scroll-view).
#### useSheet
Use this to control the sheet programatically.
void',
description: `Control the position of the sheet.`,
},
]}
/>
## Notes
For Android you need to manually re-propagate any context when using `modal`. This is because React Native doesn't support portals yet.
## components/sheet/1.123.18
---
title: Sheet
description: A bottom sheet that animates.
name: sheet
component: Sheet
package: sheet
demoName: Sheet
---
```tsx hero template=Sheet
```
## Installation
Sheet is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/sheet
```
### Anatomy
```tsx
import { Sheet } from 'tamagui' // or '@tamagui/sheet'
export default () => (
{/* ...inner contents */}
)
```
### API
#### <Sheet />
Contains every component for the sheet.
void',
description: `Called on change open, controlled or uncontrolled.`,
},
{
name: 'position',
type: 'number',
description: `Controlled position, set to an index of snapPoints.`,
},
{
name: 'defaultPosition',
type: 'number',
description: `Uncontrolled default position on mount.`,
},
{
name: 'snapPoints',
type: 'number[]',
default: `[80, 10]`,
description: `Array of numbers, 0-100 that corresponds to % of the screen it should take up. Should go from most visible to least visible in order. Use "open" prop for fully closed.`,
},
{
name: 'onPositionChange',
type: '(position: number) => void',
description: `Called on change position, controlled or uncontrolled.`,
},
{
name: 'dismissOnOverlayPress',
type: 'boolean',
default: 'true',
description: `Controls tapping on the overlay to close, defaults to true.`,
},
{
name: 'animationConfig',
type: 'Animated.SpringAnimationConfig',
default: 'true',
description: `Customize the spring used, passed to react-native Animated.spring().`,
},
{
name: 'native',
type: 'boolean | "ios"[]',
description: `(iOS only) Render to a native sheet, must install native dependency first.`,
},
{
name: 'disableDrag',
type: 'boolean',
description: `Disables all touch events to drag the sheet.`,
},
{
name: 'modal',
type: 'boolean',
description: `Renders sheet into the root of your app instead of inline.`,
},
{
name: 'dismissOnSnapToBottom',
type: 'boolean',
description: `Adds a snap point to the end of your snap points set to "0", that when snapped to will set open to false (uncontrolled) and call onOpenChange with false (controlled).`,
},
{
name: 'forceRemoveScrollEnabled',
type: 'boolean',
default: 'false',
description: `By default. Tamagui uses react-remove-scroll to prevent anything outside the sheet scrolling. This can cause some issues so you can override the behavior with this prop (either true or false).`,
},
{
name: 'portalProps',
type: 'Object',
description: `YStack props that can be passed to the Portal that sheet uses when in modal mode.`,
},
{
name: 'moveOnKeyboardChange',
type: 'boolean',
default: 'false',
description:
'Native-only flag that will make the sheet move up when the mobile keyboard opens so the focused input remains visible.',
},
]}
/>
#### <Overlay />
Displays behind Frame. Extends [YStack](/docs/components/stacks).
#### <Frame />
Contains the content. Extends [YStack](/docs/components/stacks).
#### <Handle />
Shows a handle above the frame by default, on tap it will cycle between `snapPoints` but this can be overridden with `onPress`.
Extends [XStack](/docs/components/stacks).
#### <Scrollview />
Allows scrolling within Sheet. Extends [Scrollview](/docs/components/scroll-view).
### Notes
For Android you need to manually re-propagate any context when using `modal`. This is because React Native doesn't support portals yet.
### Native support
We've deprecated the `native` prop in favor of using Adapt.
## components/sheet/1.130.0
---
title: Sheet
description: A bottom sheet that animates.
name: sheet
component: Sheet
package: sheet
demoName: Sheet
---
```tsx hero template=Sheet
```
## Installation
Sheet is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/sheet
```
### Anatomy
```tsx
import { Sheet } from 'tamagui' // or '@tamagui/sheet'
export default () => (
{/* ...inner contents */}
)
```
### API
#### <Sheet />
Contains every component for the sheet.
void',
description: `Called on change open, controlled or uncontrolled.`,
},
{
name: 'position',
type: 'number',
description: `Controlled position, set to an index of snapPoints.`,
},
{
name: 'defaultPosition',
type: 'number',
description: `Uncontrolled default position on mount.`,
},
{
name: 'snapPoints',
type: 'number[]',
default: `[80, 10]`,
description: `Array of numbers, 0-100 that corresponds to % of the screen it should take up. Should go from most visible to least visible in order. Use "open" prop for fully closed.`,
},
{
name: 'onPositionChange',
type: '(position: number) => void',
description: `Called on change position, controlled or uncontrolled.`,
},
{
name: 'dismissOnOverlayPress',
type: 'boolean',
default: 'true',
description: `Controls tapping on the overlay to close, defaults to true.`,
},
{
name: 'animationConfig',
type: 'Animated.SpringAnimationConfig',
default: 'true',
description: `Customize the spring used, passed to react-native Animated.spring().`,
},
{
name: 'native',
type: 'boolean | "ios"[]',
description: `(iOS only) Render to a native sheet, must install native dependency first.`,
},
{
name: 'disableDrag',
type: 'boolean',
description: `Disables all touch events to drag the sheet.`,
},
{
name: 'modal',
type: 'boolean',
description: `Renders sheet into the root of your app instead of inline.`,
},
{
name: 'dismissOnSnapToBottom',
type: 'boolean',
description: `Adds a snap point to the end of your snap points set to "0", that when snapped to will set open to false (uncontrolled) and call onOpenChange with false (controlled).`,
},
{
name: 'forceRemoveScrollEnabled',
type: 'boolean',
default: 'false',
description: `By default. Tamagui uses react-remove-scroll to prevent anything outside the sheet scrolling. This can cause some issues so you can override the behavior with this prop (either true or false).`,
},
{
name: 'portalProps',
type: 'Object',
description: `YStack props that can be passed to the Portal that sheet uses when in modal mode.`,
},
{
name: 'moveOnKeyboardChange',
type: 'boolean',
default: 'false',
description:
'Native-only flag that will make the sheet move up when the mobile keyboard opens so the focused input remains visible.',
},
{
name: 'preferAdaptParentOpenState',
type: 'boolean',
default: 'false',
description: `By default Sheet will prefer the open prop over a parent component that is controlling it via Adapt. In general if you want to Adapt to a sheet, you'd leave the open prop undefined. If you'd like to have the parent override the prop you've set manually on Sheet, set this to true.`,
},
]}
/>
#### <Overlay />
Displays behind Frame. Extends [YStack](/docs/components/stacks).
#### <Frame />
Contains the content. Extends [YStack](/docs/components/stacks).
#### <Handle />
Shows a handle above the frame by default, on tap it will cycle between
`snapPoints` but this can be overridden with `onPress`.
Extends [XStack](/docs/components/stacks).
#### <ScrollView />
Allows scrolling within Sheet. Extends
[Scrollview](/docs/components/scroll-view).
### Notes
For Android you need to manually re-propagate any context when using `modal`.
This is because React Native doesn't support portals yet.
### Native support
We've deprecated the `native` prop in favor of using Adapt.
## components/sheet/1.21.0
---
title: Sheet
description: A simple sheet component
name: sheet
component: Sheet
package: sheet
demoName: Sheet
---
# Sheet
A bottom sheet that slides up
```tsx hero template=Sheet
```
### Anatomy
```tsx
import { Sheet } from 'tamagui' // or '@tamagui/sheet'
export default () => (
{/* ...inner contents */}
)
```
### API
#### <Sheet />
Contains every component for the sheet.
void',
description: `Called on change open, controlled or uncontrolled.`,
},
{
name: 'position',
type: 'number',
description: `Controlled position, set to an index of snapPoints.`,
},
{
name: 'defaultPosition',
type: 'number',
description: `Uncontrolled default position on mount.`,
},
{
name: 'snapPoints',
type: 'number[]',
default: `[80, 10]`,
description: `Array of numbers, 0-100 that corresponds to % of the screen it should take up. Should go from most visible to least visible in order. Use "open" prop for fully closed.`,
},
{
name: 'onPositionChange',
type: '(position: number) => void',
description: `Called on change position, controlled or uncontrolled.`,
},
{
name: 'dismissOnOverlayPress',
type: 'boolean',
default: 'true',
description: `Controls tapping on the overlay to close, defaults to true.`,
},
{
name: 'animationConfig',
type: 'Animated.SpringAnimationConfig',
default: 'true',
description: `Customize the spring used, passed to react-native Animated.spring().`,
},
{
name: 'native',
type: 'boolean | "ios"[]',
description: `(iOS only) Render to a native sheet, must install native dependency first.`,
},
{
name: 'disableDrag',
type: 'boolean',
description: `Disables all touch events to drag the sheet.`,
},
{
name: 'modal',
type: 'boolean',
description: `Renders sheet into the root of your app instead of inline.`,
},
{
name: 'dismissOnSnapToBottom',
type: 'boolean',
description: `Adds a snap point to the end of your snap points set to "0", that when snapped to will set open to false (uncontrolled) and call onOpenChange with false (controlled).`,
},
{
name: 'forceRemoveScrollEnabled',
type: 'boolean',
default: 'false',
description: `By default. Tamagui uses react-remove-scroll to prevent anything outside the sheet scrolling. This can cause some issues so you can override the behavior with this prop (either true or false).`,
},
{
name: 'portalProps',
type: 'Object',
description: `YStack props that can be passed to the Portal that sheet uses when in modal mode.`,
},
{
name: 'moveOnKeyboardChange',
type: 'boolean',
default: 'false',
description:
'Native-only flag that will make the sheet move up when the mobile keyboard opens so the focused input remains visible.',
},
]}
/>
#### <Overlay />
Displays behind Frame. Extends [YStack](/docs/components/stacks).
#### <Frame />
Contains the content. Extends [YStack](/docs/components/stacks).
#### <Handle />
Shows a handle above the frame by default, on tap it will cycle between `snapPoints` but this can be overridden with `onPress`.
Extends [XStack](/docs/components/stacks).
#### <Scrollview />
Allows scrolling within Sheet. Extends [Scrollview](/docs/components/scroll-view).
### Notes
For Android you need to manually re-propagate any context when using `modal`. This is because React Native doesn't support portals yet.
## components/sheet/1.27.0
---
title: Sheet
description: A simple sheet component
name: sheet
component: Sheet
package: sheet
demoName: Sheet
---
# Sheet
A bottom sheet that slides up
```tsx hero template=Sheet
```
## Installation
Sheet is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/sheet
```
## Anatomy
```tsx
import { Sheet } from 'tamagui' // or '@tamagui/sheet'
export default () => (
{/* ...inner contents */}
)
```
## Unstyled
Adding the `unstyled` prop to your Handle, Overlay or Frame will turn off the default styles allowing you to customize without having to override any of the built-in styling.
## Headless with `createSheet`
Using the `createSheet` export, you can create a fully custom sheet without using any of the default styles. This is similar to `unstyled`, but it lets you also control the `open` variant.
Here's an example:
```tsx
import { Stack, styled } from '@tamagui/core'
import { createSheet } from '@tamagui/sheet'
const Handle = styled(Stack, {
variants: {
open: {
true: {
opacity: 0.35,
},
false: {
opacity: 0.5,
},
},
} as const,
})
const Overlay = styled(Stack, {
variants: {
open: {
true: {
opacity: 1,
pointerEvents: 'auto',
},
false: {
opacity: 0,
pointerEvents: 'none',
},
},
} as const,
})
const Frame = styled(Stack, {
backgroundColor: '$background',
// can add open variant as well
})
export const Sheet = createSheet({
Frame,
Handle,
Overlay,
})
```
## Native support
Sheets now support rendering to a native iOS sheet, while still rendering any of your React Native content inside of them.
Because Metro doesn't support conditional imports and we don't want to make `tamagui` enforce installing native dependencies in order to get started, there's an install step:
```sh
yarn add react-native-ios-modal
pod install
# rebuild your app (expo ios, or use react-native cli)
```
And set it up as follows:
```tsx
import { Sheet, setupNativeSheet } from '@tamagui/sheet'
import { ModalView } from 'react-native-ios-modal'
setupNativeSheet('ios', ModalView)
export default (
{/* The rest of your sheet views, see Anatomy, example and props API */}
)
```
## API Reference
### Sheet
Contains every component for the sheet.
void',
description: `Called on change open, controlled or uncontrolled.`,
},
{
name: 'position',
type: 'number',
description: `Controlled position, set to an index of snapPoints.`,
},
{
name: 'defaultPosition',
type: 'number',
description: `Uncontrolled default position on mount.`,
},
{
name: 'snapPoints',
type: 'number[]',
default: `[80, 10]`,
description: `Array of numbers, 0-100 that corresponds to % of the screen it should take up. Should go from most visible to least visible in order. Use "open" prop for fully closed.`,
},
{
name: 'onPositionChange',
type: '(position: number) => void',
description: `Called on change position, controlled or uncontrolled.`,
},
{
name: 'dismissOnOverlayPress',
type: 'boolean',
default: 'true',
description: `Controls tapping on the overlay to close, defaults to true.`,
},
{
name: 'animationConfig',
type: 'Animated.SpringAnimationConfig',
default: 'true',
description: `Customize the spring used, passed to react-native Animated.spring().`,
},
{
name: 'native',
type: 'boolean | "ios"[]',
description: `(iOS only) Render to a native sheet, must install native dependency first.`,
},
{
name: 'disableDrag',
type: 'boolean',
description: `Disables all touch events to drag the sheet.`,
},
{
name: 'modal',
type: 'boolean',
description: `Renders sheet into the root of your app instead of inline.`,
},
{
name: 'dismissOnSnapToBottom',
type: 'boolean',
description: `Adds a snap point to the end of your snap points set to "0", that when snapped to will set open to false (uncontrolled) and call onOpenChange with false (controlled).`,
},
{
name: 'forceRemoveScrollEnabled',
type: 'boolean',
default: 'false',
description: `By default. Tamagui uses react-remove-scroll to prevent anything outside the sheet scrolling. This can cause some issues so you can override the behavior with this prop (either true or false).`,
},
{
name: 'portalProps',
type: 'Object',
description: `YStack props that can be passed to the Portal that sheet uses when in modal mode.`,
},
{
name: 'moveOnKeyboardChange',
type: 'boolean',
default: 'false',
description:
'Native-only flag that will make the sheet move up when the mobile keyboard opens so the focused input remains visible.',
},
]}
/>
### Sheet.Overlay
Displays behind Frame. Extends [YStack](/docs/components/stacks).
### Sheet.Frame
Contains the content. Extends [YStack](/docs/components/stacks).
### Sheet.Handle
Shows a handle above the frame by default, on tap it will cycle between `snapPoints` but this can be overridden with `onPress`.
Extends [XStack](/docs/components/stacks).
### Sheet.ScrollView
Allows scrolling within Sheet. Extends [Scrollview](/docs/components/scroll-view).
#### useSheet
Use this to control the sheet programatically.
void',
description: `Control the position of the sheet.`,
},
]}
/>
## Notes
For Android you need to manually re-propagate any context when using `modal`. This is because React Native doesn't support portals yet.
## components/sheet/1.59.0
---
title: Sheet
description: A simple sheet component
name: sheet
component: Sheet
package: sheet
demoName: Sheet
---
# Sheet
A bottom sheet that slides up
```tsx hero template=Sheet
```
## Installation
Sheet is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/sheet
```
### PortalProvider
When rendering into root of app instead of inline, you'll first need to install the `@tamagui/portal` package:
```bash
npm install @tamagui/portal
```
Then add `PortalProvider` to the root of your app:
```tsx fileName="App.tsx"
import { PortalProvider } from '@tamagui/portal'
import YourApp from './components/YourApp'
function App() {
return (
)
}
export default App
```
## Anatomy
```tsx
import { Sheet } from 'tamagui' // or '@tamagui/sheet'
export default () => (
{/* ...inner contents */}
)
```
## Snap points
By default, snap points are treated as percentages.
```tsx
// 85% and 50%
```
The behavior of snap points can be changed by setting the `snapPointsMode` prop to any of these values:
- **percent** (default) - Snap points are percentages of the parent container or screen as numbers
- **constant** - Snap points are raw pixel values as numbers
- **fit** - The sheet is constrained to the content's natural height without the `snapPoints` prop
- **mixed** - Snap points can be either numbers (pixels), percentages as strings (ex: `"50%"`), or `"fit"` for fit behavior
Snap points should be ordered from largest to smallest (most visible to least visible). When using `mixed` mode with the `"fit"` as a snap point, it must be the first and largest snap point.
## Unstyled
Adding the `unstyled` prop to your Handle, Overlay or Frame will turn off the default styles allowing you to customize without having to override any of the built-in styling.
## Headless with `createSheet`
Using the `createSheet` export, you can create a fully custom sheet without using any of the default styles. This is similar to `unstyled`, but it lets you also control the `open` variant.
Here's an example:
```tsx
import { Stack, styled } from '@tamagui/core'
import { createSheet } from '@tamagui/sheet'
const Handle = styled(Stack, {
variants: {
open: {
true: {
opacity: 0.35,
},
false: {
opacity: 0.5,
},
},
} as const,
})
const Overlay = styled(Stack, {
variants: {
open: {
true: {
opacity: 1,
pointerEvents: 'auto',
},
false: {
opacity: 0,
pointerEvents: 'none',
},
},
} as const,
})
const Frame = styled(Stack, {
backgroundColor: '$background',
// can add open variant as well
})
export const Sheet = createSheet({
Frame,
Handle,
Overlay,
})
```
## Native support
Sheets now support rendering to a native iOS sheet, while still rendering any of your React Native content inside of them.
Because Metro doesn't support conditional imports and we don't want to make `tamagui` enforce installing native dependencies in order to get started, there's an install step:
```sh
yarn add react-native-ios-modal
pod install
# rebuild your app (expo ios, or use react-native cli)
```
And set it up as follows:
```tsx
import { Sheet, setupNativeSheet } from '@tamagui/sheet'
import { ModalView } from 'react-native-ios-modal'
setupNativeSheet('ios', ModalView)
export default (
{/* The rest of your sheet views, see Anatomy, example and props API */}
)
```
## API Reference
### Sheet
Contains every component for the sheet.
void',
description: `Called on change open, controlled or uncontrolled.`,
},
{
name: 'position',
type: 'number',
description: `Controlled position, set to an index of snapPoints.`,
},
{
name: 'defaultPosition',
type: 'number',
description: `Uncontrolled default position on mount.`,
},
{
name: 'snapPoints',
type: '(number | string)[] | undefined',
default: `[80]`,
description: `Array of values representing different sizes for the sheet to snap to. Not used in 'fit' mode. See docs above for usage information.`,
},
{
name: 'snapPointsMode',
type: '"percent" | "constant" | "fit" | "mixed"',
default: '"percent"',
description: `Alters the behavior of the 'snapPoints' prop. See docs above for usage information.`,
},
{
name: 'onPositionChange',
type: '(position: number) => void',
description: `Called on change position, controlled or uncontrolled.`,
},
{
name: 'dismissOnOverlayPress',
type: 'boolean',
default: 'true',
description: `Controls tapping on the overlay to close, defaults to true.`,
},
{
name: 'animationConfig',
type: 'Animated.SpringAnimationConfig',
default: 'true',
description: `Customize the spring used, passed to react-native Animated.spring().`,
},
{
name: 'native',
type: 'boolean | "ios"[]',
description: `(iOS only) Render to a native sheet, must install native dependency first.`,
},
{
name: 'disableDrag',
type: 'boolean',
description: `Disables all touch events to drag the sheet.`,
},
{
name: 'modal',
type: 'boolean',
description: `Renders sheet into the root of your app instead of inline.`,
},
{
name: 'dismissOnSnapToBottom',
type: 'boolean',
description: `Adds a snap point to the end of your snap points set to "0", that when snapped to will set open to false (uncontrolled) and call onOpenChange with false (controlled).`,
},
{
name: 'forceRemoveScrollEnabled',
type: 'boolean',
default: 'false',
description: `By default. Tamagui uses react-remove-scroll to prevent anything outside the sheet scrolling. This can cause some issues so you can override the behavior with this prop (either true or false).`,
},
{
name: 'portalProps',
type: 'Object',
description: `YStack props that can be passed to the Portal that sheet uses when in modal mode.`,
},
{
name: 'moveOnKeyboardChange',
type: 'boolean',
default: 'false',
description:
'Native-only flag that will make the sheet move up when the mobile keyboard opens so the focused input remains visible.',
},
{
name: 'unmountChildrenWhenHidden',
type: 'boolean',
default: 'false',
description:
'Flag to enable unmounting the children after the exit animation has completed.',
},
]}
/>
If using `modal={true}` (which is `true` by default), refer to the [PortalProvider
installation](/ui/sheet/1.59.0#portalprovider) for more information.
### Sheet.Overlay
Displays behind Frame. Extends [YStack](/docs/components/stacks).
### Sheet.Frame
Contains the content. Extends [YStack](/docs/components/stacks).
### Sheet.Handle
Shows a handle above the frame by default, on tap it will cycle between `snapPoints` but this can be overridden with `onPress`.
Extends [XStack](/docs/components/stacks).
### Sheet.ScrollView
Allows scrolling within Sheet. Extends [ScrollView](/docs/components/scroll-view).
#### useSheet
Use this to control the sheet programatically.
void',
description: `Control the position of the sheet.`,
},
]}
/>
## Notes
For Android you need to manually re-propagate any context when using `modal`. This is because React Native doesn't support portals yet.
## components/sheet/1.9.18
---
title: Sheet
description: A simple sheet component
name: sheet
component: Sheet
package: sheet
demoName: Sheet
---
# Sheet
A bottom sheet that slides up.
```tsx hero template=Sheet
```
### Anatomy
```tsx
import { Sheet } from 'tamagui' // or '@tamagui/sheet'
export default () => (
{/* ...inner contents */}
)
```
### API
#### <Sheet />
Contains every component for the sheet.
void',
description: `Called on change open, controlled or uncontrolled.`,
},
{
name: 'position',
type: 'number',
description: `Controlled position, set to an index of snapPoints.`,
},
{
name: 'defaultPosition',
type: 'number',
description: `Uncontrolled default position on mount.`,
},
{
name: 'snapPoints',
type: 'number[]',
default: `[80, 10]`,
description: `Array of numbers, 0-100 that corresponds to % of the screen it should take up. Should go from most visible to least visible in order. Use "open" prop for fully closed.`,
},
{
name: 'onPositionChange',
type: '(position: number) => void',
description: `Called on change position, controlled or uncontrolled.`,
},
{
name: 'dismissOnOverlayPress',
type: 'boolean',
default: 'true',
description: `Controls tapping on the overlay to close, defaults to true.`,
},
{
name: 'animationConfig',
type: 'Animated.SpringAnimationConfig',
default: 'true',
description: `Customize the spring used, passed to react-native Animated.spring().`,
},
{
name: 'disableDrag',
type: 'boolean',
description: `Disables all touch events to drag the sheet.`,
},
{
name: 'modal',
type: 'boolean',
description: `Renders sheet into the root of your app instead of inline.`,
},
{
name: 'dismissOnSnapToBottom',
type: 'boolean',
description: `Adds a snap point to the end of your snap points set to "0", that when snapped to will set open to false (uncontrolled) and call onOpenChange with false (controlled).`,
},
{
name: 'forceRemoveScrollEnabled',
type: 'boolean',
default: 'false',
description: `By default. Tamagui uses react-remove-scroll to prevent anything outside the sheet scrolling. This can cause some issues so you can override the behavior with this prop (either true or false).`,
},
{
name: 'portalProps',
type: 'Object',
description: `YStack props that can be passed to the Portal that sheet uses when in modal mode.`,
},
{
name: 'moveOnKeyboardChange',
type: 'boolean',
default: 'false',
description:
'Native-only flag that will make the sheet move up when the mobile keyboard opens so the focused input remains visible.',
},
]}
/>
#### <Overlay />
Displays behind Frame. Extends [YStack](/docs/components/stacks).
#### <Frame />
Contains the content. Extends [YStack](/docs/components/stacks).
#### <Handle />
Shows a handle above the frame by default, on tap it will cycle between `snapPoints` but this can be overridden with `onPress`.
Extends [XStack](/docs/components/stacks).
#### <Scrollview />
Allows scrolling within Sheet. Extends [Scrollview](/docs/components/scroll-view).
### Notes
For Android you need to manually re-propagate any context when using `modal`. This is because React Native doesn't support portals yet.
## components/sheet/2.0.0
---
title: Sheet
description: A bottom sheet that animates
name: sheet
component: Sheet
package: sheet
demoName: Sheet
---
```tsx hero template=Sheet
```
Sheet is a bottom panel that slides up from the bottom of the screen, commonly used for mobile-friendly dialogs and action menus. It supports drag-to-dismiss, multiple snap points, and [automatically stacks](/ui/z-index) above other content.
## Installation
Sheet is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/sheet
```
For native apps, we recommend [setting up native
portals](/docs/components/portal#native-portal-setup-recommended) to preserve React
context inside Sheet content.
## Anatomy
```tsx
import { Sheet } from 'tamagui' // or '@tamagui/sheet'
export default () => (
{/* ...inner contents */}
)
```
## API Reference
### Sheet
Contains every component for the sheet.
void',
description: `Called on change open, controlled or uncontrolled.`,
},
{
name: 'position',
type: 'number',
description: `Controlled position, set to an index of snapPoints.`,
},
{
name: 'defaultPosition',
type: 'number',
description: `Uncontrolled default position on mount.`,
},
{
name: 'snapPoints',
type: 'number[]',
default: `[80, 10]`,
description: `Array of numbers, 0-100 that corresponds to % of the screen it should take up. Should go from most visible to least visible in order. Use "open" prop for fully closed.`,
},
{
name: 'onPositionChange',
type: '(position: number) => void',
description: `Called on change position, controlled or uncontrolled.`,
},
{
name: 'dismissOnOverlayPress',
type: 'boolean',
default: 'true',
description: `Controls tapping on the overlay to close, defaults to true.`,
},
{
name: 'animationConfig',
type: 'Animated.SpringAnimationConfig',
default: 'true',
description: `Customize the spring used, passed to react-native Animated.spring().`,
},
{
name: 'native',
type: 'boolean | "ios"[]',
description: `(iOS only) Render to a native sheet, must install native dependency first.`,
},
{
name: 'disableDrag',
type: 'boolean',
description: `Disables all touch events to drag the sheet.`,
},
{
name: 'modal',
type: 'boolean',
description: `Renders sheet into the root of your app instead of inline.`,
},
{
name: 'dismissOnSnapToBottom',
type: 'boolean',
description: `Adds a snap point to the end of your snap points set to "0", that when snapped to will set open to false (uncontrolled) and call onOpenChange with false (controlled).`,
},
{
name: 'disableRemoveScroll',
type: 'boolean',
default: 'false',
description: `Disables the RemoveScroll behavior that prevents body scrolling while sheet is open. By default, RemoveScroll is enabled when the sheet is open and modal.`,
},
{
name: 'forceRemoveScrollEnabled',
type: 'boolean',
default: 'false',
deprecated: true,
description: `@deprecated Use \`disableRemoveScroll\` instead. By default. Tamagui uses react-remove-scroll to prevent anything outside the sheet scrolling. This can cause some issues so you can override the behavior with this prop (either true or false).`,
},
{
name: 'portalProps',
type: 'Object',
description: `YStack props that can be passed to the Portal that sheet uses when in modal mode.`,
},
{
name: 'moveOnKeyboardChange',
type: 'boolean',
default: 'false',
description:
'Native-only flag that will make the sheet move up when the mobile keyboard opens so the focused input remains visible.',
},
{
name: 'preferAdaptParentOpenState',
type: 'boolean',
default: 'false',
description: `By default Sheet will prefer the open prop over a parent component that is controlling it via Adapt. In general if you want to Adapt to a sheet, you'd leave the open prop undefined. If you'd like to have the parent override the prop you've set manually on Sheet, set this to true.`,
},
]}
/>
### Sheet.Overlay
Displays behind Frame. Extends [YStack](/docs/components/stacks).
### Sheet.Frame
Contains the content. Extends [YStack](/docs/components/stacks).
### Sheet.Handle
Shows a handle above the frame by default. On tap, it will cycle between
`snapPoints`, but this can be overridden with `onPress`.
Extends [XStack](/docs/components/stacks).
### Sheet.ScrollView
Allows scrolling within Sheet. Extends
[ScrollView](/docs/components/scroll-view).
## Native Gesture Handler Integration
For the best gesture experience on iOS and Android, Sheet supports optional integration with `react-native-gesture-handler`. This provides:
- **Smooth scroll-to-drag handoffs** - Seamlessly transition between scrolling content and dragging the sheet
- **No gesture conflicts** - Sheet and ScrollView gestures coordinate properly
- **Native-quality feel** - Matches the behavior of system sheets
#### Setup
1. Install `react-native-gesture-handler`:
```bash
npm install react-native-gesture-handler
```
2. Add the setup import to your app entry point (before any Tamagui imports):
```tsx
// App.tsx or index.js
import '@tamagui/native/setup-gesture-handler'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
export default function App() {
return (
{/* Your app */}
)
}
```
That's it! Sheet will automatically detect and use the native gesture handler when available.
#### Using Sheet.ScrollView
When using scrollable content inside a Sheet, use `Sheet.ScrollView` for proper gesture coordination:
```tsx
{/* Scrollable content */}
```
This ensures:
- Scrolling up at the top of content works naturally
- Dragging down when scroll is at top drags the sheet
- Direction changes mid-gesture work smoothly
#### Without Gesture Handler
If you don't set up `react-native-gesture-handler`, Sheet falls back to React Native's built-in `PanResponder`. This works well for basic use cases but has some limitations on iOS where scroll and pan gestures can occasionally conflict.
## Notes
For Android you need to manually re-propagate any context when using `modal`.
This is because React Native doesn't support portals yet.
## Native Support
We've deprecated the `native` prop in favor of using Adapt.
## components/slider/1.0.0
---
title: Slider
description: A simple slider component
name: slider
component: Slider
package: slider
demoName: Slider
---
# Slider
Drag to set values, vertically or horizontally
```tsx hero template=Slider
```
## Installation
Slider is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/slider
```
## Usage
Slider comes as multiple components that ship with default styles and are sizable. The `size` prop on `` will automatically pass size down to all the sub-components.
```tsx
import { Slider } from 'tamagui'
export default () => (
)
```
You can also optionally style any component, either using inline style props or by wrapping with `styled`:
```tsx
import { Slider, styled } from 'tamagui'
const CustomSliderTrack = styled(Slider.Track, {
backgroundColor: 'red',
})
export default () => (
)
```
## API Reference
### Slider
Contains every component for the slider.
### Slider.Track
`Slider.Track` Inherits `SizableStack`, extending all the default [props](/docs/intro/props).
### Slider.TrackActive
`Slider.Track` Inherits `Stack`, extending all the default [props](/docs/intro/props).
### Slider.Thumb
`Slider.Track` Inherits `SizableStack`, extending all the default [props](/docs/intro/props), adding:
## components/slider/1.45.0
---
title: Slider
description: Drag to set values, vertically or horizontally.
name: slider
component: Slider
package: slider
demoName: Slider
---
```tsx hero template=Slider
```
## Installation
Slider is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/slider
```
## Usage
Slider comes as multiple components that ship with default styles and are sizable. The `size` prop on `` will automatically pass size down to all the sub-components.
```tsx
import { Slider } from 'tamagui'
export default () => (
)
```
You can also optionally style any component, either using inline style props or by wrapping with `styled`:
```tsx
import { Slider, styled } from 'tamagui'
const CustomSliderTrack = styled(Slider.Track, {
backgroundColor: 'red',
})
export default () => (
)
```
## API Reference
### Slider
Contains every component for the slider.
void`,
description: `Called on slide start.`,
},
{
name: 'onSlideMove',
required: false,
type: `(event: GestureReponderEvent, value: number) => void`,
description: `Called on slide move.`,
},
{
name: 'onSlideEnd',
required: false,
type: `(event: GestureReponderEvent, value: number) => void`,
description: `Called on slide end.`,
},
]}
/>
### Slider.Track
`Slider.Track` Inherits `SizableStack`, extending all the default [props](/docs/intro/props).
### Slider.TrackActive
`Slider.TrackActive` Inherits `Stack`, extending all the default [props](/docs/intro/props).
### Slider.Thumb
`Slider.Thumb` Inherits `SizableStack`, extending all the default [props](/docs/intro/props), adding:
## components/slider/2.0.0
---
title: Slider
description: Drag to set values, vertically or horizontally
name: slider
component: Slider
package: slider
demoName: Slider
---
```tsx hero template=Slider
```
## Installation
Slider is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/slider
```
## Usage
Slider comes as multiple components that ship with default styles and are sizable. The `size` prop on `` will automatically pass size down to all the sub-components.
```tsx
import { Slider } from 'tamagui'
export default () => (
)
```
You can also optionally style any component, either using inline style props or by wrapping with `styled`:
```tsx
import { Slider, styled } from 'tamagui'
const CustomSliderTrack = styled(Slider.Track, {
backgroundColor: 'red',
})
export default () => (
)
```
## Vertical Slider on iOS
When using a vertical slider on iOS, you need to pass safe area insets to `TamaguiProvider` for proper pointer position calculation. Without this, the slider thumb may not track your finger correctly due to iOS safe area offsets.
```tsx
import { TamaguiProvider } from 'tamagui'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { config } from './tamagui.config'
function App() {
const insets = useSafeAreaInsets()
return (
{/* Your app content */}
)
}
```
Then you can use vertical sliders normally:
```tsx
import { Slider, XStack } from 'tamagui'
export default () => (
)
```
This is only required on iOS. On Android and web, the slider works correctly without
passing insets.
## API Reference
### Slider
Contains every component for the slider.
void`,
description: `Called on slide start.`,
},
{
name: 'onSlideMove',
required: false,
type: `(event: GestureReponderEvent, value: number) => void`,
description: `Called on slide move.`,
},
{
name: 'onSlideEnd',
required: false,
type: `(event: GestureReponderEvent, value: number) => void`,
description: `Called on slide end.`,
},
]}
/>
### Slider.Track
Slider.Track inherits `SizableStack`, extending all the default [props](/docs/intro/props).
### Slider.TrackActive
Slider.TrackActive inherits `Stack`, extending all the default [props](/docs/intro/props).
### Slider.Thumb
Slider.Thumb inherits `SizableStack`, extending all the default [props](/docs/intro/props), adding:
## components/spinner/1.0.0
---
title: Spinner
description: Render a loading indicator.
name: spinner
component: Spinner
demoName: Spinner
---
```tsx hero template=Spinner
```
## Installation
Spinner is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/spinner
```
Note that due to the fact that Spinner is an extension of React Native [ActivityIndicator](https://reactnative.dev/docs/activityindicator), and that only accepts size `small` or `large`, we are currently limited to just these sizes.
```tsx
import { Button, Spinner } from 'tamagui'
export default () =>
```
## API Reference
### Spinner
Spinner extends [YStack](/docs/components/stacks), getting [Tamagui standard props](/docs/intro/props), plus:
## components/spinner/2.0.0
---
title: Spinner
description: Render a loading indicator
name: spinner
component: Spinner
package: spinner
demoName: Spinner
---
```tsx hero template=Spinner
```
## Installation
Spinner is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/spinner
```
Note that due to the fact that Spinner is an extension of React Native [ActivityIndicator](https://reactnative.dev/docs/activityindicator), and that only accepts size `small` or `large`, we are currently limited to just these sizes.
## Usage
```tsx
import { Button, Spinner } from 'tamagui'
export default () =>
```
## API Reference
### Spinner
Spinner extends [YStack](/docs/components/stacks), getting [Tamagui standard props](/docs/intro/props), plus:
## components/stacks/1.0.0
---
title: Stacks
description: An optional base for creating flex-based layouts.
name: stacks
component: Stacks
package: stacks
demoName: Stacks
---
```tsx hero template=Stacks
```
Tamagui UI includes optional stack views - XStack, YStack and ZStack. They extend directly off the [View](/docs/core/view-and-text) from `@tamagui/core`.
Stack props accept [every prop from react-native-web](https://necolas.github.io/react-native-web/docs/view/) View, as well as all [the style properties Tamagui supports](/docs/intro/props).
In this example you'd show three `YStack` elements spaced out.
## Installation
Stacks is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/stacks
```
```tsx
import { XStack, YStack } from 'tamagui'
export default () => (
)
```
To see all the style properties supported, see the [Props](/docs/intro/props) documentation.
### Fuller example
An example using a wide variety of style properties:
```tsx
import { Text, XStack, YStack } from 'tamagui'
export default () => (
HelloWorld
)
```
## API Reference
### XStack, YStack, ZStack
Beyond the [Tamagui Props](/docs/intro/props), the stacks add just two variants:
Sets position: absolute, top: 0, left: 0, right: 0, bottom: 0.
),
},
{
name: 'elevation',
required: false,
type: 'number | tokens.size',
description: (
Sets a natural looking shadow that expands out and away as the size gets bigger.
),
},
]}
/>
## components/stacks/2.0.0
---
title: Stacks
description: An optional base for creating flex-based layouts
name: stacks
component: Stacks
package: stacks
demoName: Stacks
---
```tsx hero template=Stacks
```
Tamagui UI includes optional stack views - XStack, YStack and ZStack. They
extend directly off the [View](/docs/core/view-and-text) from `@tamagui/core`,
and so accept all [style properties](/docs/intro/props).
In this example you'd show three `YStack` elements spaced out.
## Installation
Stacks is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/stacks
```
## Usage
```tsx
import { XStack, YStack } from 'tamagui'
export default () => (
)
```
To see all the style properties supported, see the [Props](/docs/intro/props)
documentation.
### Fuller Example
An example using a wide variety of style properties:
```tsx
import { Text, XStack, YStack } from 'tamagui'
export default () => (
HelloWorld
)
```
## API Reference
### XStack, YStack, ZStack
Beyond the [Tamagui Props](/docs/intro/props), the stacks add just two variants:
Deprecated: use inset: 0, position: 'absolute' instead.
),
},
{
name: 'elevation',
required: false,
type: 'number | tokens.size',
description: (
Sets a natural looking shadow that expands out and away as the size gets bigger.
),
},
]}
/>
## components/switch/1.0.0
---
title: Switch
description: A simple switch component
name: switch
component: Switch
package: switch
demoName: Switch
---
# Switch
Use in forms to toggle between two states.
```tsx hero template=Switch
```
### Usage
```tsx
import { Switch } from 'tamagui'
export default () => (
)
```
### Switch props
Switchs extend Stack views inheriting all the [Tamagui standard props](/docs/intro/props), plus:
void',
},
{
name: 'unstyled',
type: 'boolean',
default: 'false',
description: `When true, remove all default tamagui styling.`,
},
]}
/>
## components/switch/1.28.0
---
title: Switch
description: A simple switch component
name: switch
component: Switch
package: switch
demoName: Switch
---
# Switch
Use in forms to toggle between two states.
```tsx hero template=Switch
```
## Installation
Switch is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/switch
```
## Usage
```tsx
import { Switch } from 'tamagui' // or '@tamagui/switch'
export default () => (
)
```
## API Reference
### Switch
Switchs extend Stack views inheriting all the [Tamagui standard props](/docs/intro/props), plus:
void',
},
{
name: 'unstyled',
type: 'boolean',
default: 'false',
description: `When true, remove all default tamagui styling.`,
},
{
name: 'native',
type: 'NativeValue<"mobile" | "ios" | "android">',
description: `Render to a native switch. (Not supported on web)`,
},
{
name: 'nativeProps',
type: 'SwitchProps (from `react-native`)',
description: `Props to pass to the native Switch;`,
},
]}
/>
### Switch.Thumb
`Switch.Thumb` extends Stack views inheriting all the [Tamagui standard props](/docs/intro/props), plus:
## components/switch/1.58.0
---
title: Switch
description: A simple switch component
name: switch
component: Switch
package: switch
demoName: Switch
---
# Switch
Use in forms to toggle between two states.
```tsx hero template=Switch
```
## Installation
Switch is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/switch
```
## Usage
```tsx
import { Switch } from 'tamagui' // or '@tamagui/switch'
export default () => (
)
```
## Headless with `createSwitch`
Using the `createSwitch` export, you can create a fully custom switch without using any of the default styles. This is similar to `unstyled`, but it doesn't assume the props `size` or `unstyled` exist, and it won't automatically apply the `active` theme.
You must pass `SwitchContext` as the `context` option to your Frame and Thumb styled components.
If you define a `checked` variant, it will apply those styles.
Here's an example:
```tsx
import { Stack, styled } from '@tamagui/core'
import { createSwitch } from '@tamagui/switch'
const Frame = styled(Stack, {
variants: {
checked: {
true: {
backgroundColor: 'yellow',
},
false: {
backgroundColor: 'green',
},
},
} as const,
})
const Thumb = styled(Stack, {
variants: {
checked: {
true: {
opacity: 1,
},
false: {
opacity: 0.5,
},
},
} as const,
})
export const Switch = createSwitch({
Frame,
Thumb,
})
```
## API Reference
### Switch
`Switch` extends Stack views inheriting all the [Tamagui standard props](/docs/intro/props), plus:
void',
},
{
name: 'unstyled',
type: 'boolean',
default: 'false',
description: `When true, remove all default tamagui styling.`,
},
{
name: 'native',
type: 'NativeValue<"mobile" | "ios" | "android">',
description: `Render to a native switch. (Not supported on web)`,
},
{
name: 'nativeProps',
type: 'SwitchProps (from `react-native`)',
description: `Props to pass to the native Switch;`,
},
]}
/>
### Switch.Thumb
`Switch.Thumb` extends Stack views inheriting all the [Tamagui standard props](/docs/intro/props), plus:
## components/switch/1.89.0
---
title: Switch
description: A toggle between two states.
name: switch
component: Switch
package: switch
demoName: Switch
---
StyledUnstyledHeadless
```tsx hero template=Switch
````
```tsx hero template=SwitchUnstyled
````
```tsx hero template=SwitchHeadless
````
## Installation
Switch is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/switch
````
Switch is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/switch
```
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 you can bring your own style library.
```bash
npm install @tamagui/switch-headless
```
## Usage
```tsx
import { Switch } from 'tamagui' // or '@tamagui/switch'
export default () => (
)
```
Using the `createSwitch` export, you can create an unstyled switch without using
any of the default styles. This is similar to the `unstyled` prop, but it
doesn't assume the props `size` or `unstyled` exist, and it won't automatically
apply the `active` theme.
You must pass `SwitchContext` as the `context` option to your Frame and Thumb
styled components.
If you define a `checked` variant, it will apply those styles.
```tsx template=SwitchUnstyled
```
Using the `useSwitch` API, you can make your own Switch from scratch.
```tsx template=SwitchHeadless
```
## API Reference
### Switch
`Switch` extends Stack views inheriting all the
[Tamagui standard props](/docs/intro/props), plus:
void',
},
{
name: 'unstyled',
type: 'boolean',
default: 'false',
description: `When true, remove all default tamagui styling.`,
},
{
name: 'native',
type: 'NativeValue<"mobile" | "ios" | "android">',
description: `Render to a native switch. (Not supported on web)`,
},
{
name: 'nativeProps',
type: 'SwitchProps (from `react-native`)',
description: `Props to pass to the native Switch;`,
},
]}
/>
### Switch.Thumb
`Switch.Thumb` extends Stack views inheriting all the
[Tamagui standard props](/docs/intro/props), plus:
{/* TODO: document createSwitch and useSwitch's API */}
## components/switch/2.0.0
---
title: Switch
description: A toggle between two states
name: switch
component: Switch
package: switch
demoName: Switch
---
StyledUnstyledHeadless
```tsx hero template=Switch
````
```tsx hero template=SwitchUnstyled
````
```tsx hero template=SwitchHeadless
````
## Installation
Switch is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/switch
````
Switch is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/switch
```
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 you can bring your own style library.
```bash
npm install @tamagui/switch-headless
```
## Usage
```tsx
import { Switch } from 'tamagui' // or '@tamagui/switch'
export default () => (
)
```
Using the `createSwitch` export, you can create an unstyled switch without using
any of the default styles. This is similar to the `unstyled` prop, but it
doesn't assume the props `size` or `unstyled` exist, and it won't automatically
apply the `active` theme.
You must pass `SwitchContext` as the `context` option to your Frame and Thumb
styled components.
If you define a `checked` variant, it will apply those styles.
```tsx template=SwitchUnstyled
```
The `useSwitch` hook provides all the state and accessibility props needed to build a custom switch with any styling solution.
```tsx template=SwitchHeadless
```
### Basic Usage
```tsx
import { useSwitch } from '@tamagui/switch-headless'
import { useState } from 'react'
import { Pressable, View } from 'react-native'
function MySwitch({ defaultChecked, onCheckedChange, ...props }) {
const [checked, setChecked] = useState(defaultChecked || false)
const { switchProps, switchRef, bubbleInput } = useSwitch(
props,
[checked, setChecked],
null
)
return (
<>
{bubbleInput}
>
)
}
```
## API Reference
### Switch
`Switch` extends Stack views inheriting all the
[Tamagui standard props](/docs/intro/props), plus:
void',
description: `Callback called when checked state changes.`,
},
{
name: 'unstyled',
type: 'boolean',
default: 'false',
description: `When true, removes all default Tamagui styling.`,
},
{
name: 'native',
type: 'NativeValue<"mobile" | "ios" | "android">',
description: `Render to a native switch. (Not supported on web)`,
},
{
name: 'nativeProps',
type: 'SwitchProps (from `react-native`)',
description: `Props to pass to the native Switch.`,
},
{
name: 'activeStyle',
type: 'ViewStyle',
description: `Styles to apply when the switch is checked/active.`,
},
{
name: 'activeTheme',
type: 'string | null',
description: `Theme to apply when the switch is checked/active.`,
},
]}
/>
### Switch.Thumb
`Switch.Thumb` extends Stack views inheriting all the
[Tamagui standard props](/docs/intro/props), plus:
### useSwitch
The `useSwitch` hook accepts three arguments:
```tsx
const { switchProps, switchRef, bubbleInput } = useSwitch(
props, // SwitchProps
state, // [checked: boolean, setChecked: (checked: boolean) => void]
ref // React.Ref
)
```
#### Props (first argument)
void',
description: `Called when switch is pressed (composed with internal handler).`,
},
]}
/>
#### State (second argument)
A tuple of `[checked, setChecked]` where:
- `checked`: Current boolean state
- `setChecked`: React state setter function
#### Return Value
| Property | Type | Description |
| ------------- | ------------------- | -------------------------------------------------------------------------- |
| `switchProps` | `object` | Props to spread on your switch element (role, aria-checked, onPress, etc.) |
| `switchRef` | `Ref` | Composed ref to attach to your switch element |
| `bubbleInput` | `ReactNode \| null` | Hidden input for form compatibility (render as sibling, web only) |
## components/tabs/1.125.35
---
title: Tabs
description: Use in pages to manage sub-pages.
name: tabs
component: Tabs
package: tabs
demoName: Tabs
---
StyledHeadless
```tsx hero template=Tabs
```
Note: Tabs have landed on v1.7 and not fully ready for runtime. Send us your feedback and we'll address it. We're marking it Beta a such as there may be hopefully minimal breaking changes as we get feedback on the API.
## Installation
Tabs is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/tabs
```
## Usage
```tsx
import { SizableText, Tabs } from 'tamagui'
export default () => (
Tab 1Tab 2
Tab 1
Tab 2
)
```
## API Reference
### Tabs
Root tabs component. Extends [Stack](/docs/components/stacks). Passing the `size` prop to this component will have effect on the descendants.
void',
description: `A function called when a new tab is selected`,
},
{
name: 'orientation',
type: '"horizontal" | "vertical"',
default: 'horizontal',
description: `The orientation the tabs are laid out.`,
},
{
name: 'dir',
type: '"ltr" | "rtl"',
description: `The direction of navigation between toolbar items`,
},
{
name: 'activationMode',
type: '"manual" | "automatic"',
default: 'automatic',
description: `Whether or not a tab is activated automatically or manually. Not applicable on mobile`,
},
]}
/>
### Tabs.List
Container for the trigger buttons. Supports scrolling by extending [Group](/docs/components/group). You can disable passing border radius to children by passing `disablePassBorderRadius`.
### Tabs.Tab
The clickable tab button that activates its corresponding content. Extends [ThemeableStack](/docs/components/stacks#themeablestack), adding:
void`,
description: `Used for making custom indicators when tab is interacted with. InteractionType is 'select' | 'focus' | 'hover'`,
},
{
name: 'disabled',
type: `boolean`,
description: `When true, prevents user interaction with the tab`,
},
{
name: 'disableActiveTheme',
type: `boolean`,
description: `When true, disables applying the 'active' theme when the tab is selected`,
},
{
name: 'unstyled',
type: `boolean`,
description: `When true, remove all default tamagui styling`,
},
]}
/>
### Tabs.Trigger
Extends [ThemeableStack](/docs/components/stacks#themeablestack), adding:
void`,
description: `Used for making custom indicators when trigger interacted with`,
},
{
name: 'unstyled',
type: `boolean`,
description: `When true, remove all default tamagui styling`,
},
]}
/>
### Tabs.Content
Where each tab's content will be shown. Extends [ThemeableStack](/docs/components/stacks#themeablestack), adding:
## Examples
### Animations
Here is a demo with more advanced animations using [AnimatePresence](/docs/core/animations#animatepresence-and-exitstyle) and [Trigger](#trigger)'s `onInteraction` prop.
```tsx hero template=TabsAdvanced
```
```tsx hero template=TabsHeadless
```
### Customization Options
When using `createTabs`, you need to provide three styled components:
- `TabsFrame`: The root container component
- `TabFrame`: The tab trigger component
- `ContentFrame`: The content container component
The created tabs component will maintain all the accessibility features and keyboard navigation while allowing you to have complete control over the visual presentation.
The headless API gives you the foundation to build completely custom tab interfaces while maintaining accessibility and interaction patterns. You can integrate it with your design system and add any custom behaviors you need.
## components/tabs/1.7.0
---
title: Tabs
description: Use in pages to manage sub-pages.
name: tabs
component: Tabs
package: tabs
demoName: Tabs
---
```tsx hero template=Tabs
```
Note: Tabs have landed on v1.7 and not fully ready for runtime. Send us your feedback and we'll address it. We're marking it Beta a such as there may be hopefully minimal breaking changes as we get feedback on the API.
## Usage
```tsx
import { SizableText, Tabs } from 'tamagui'
export default () => (
Tab 1Tab 2
Tab 1
Tab 2
)
```
## API Reference
### Tabs
Root tabs component. Extends [Stack](/docs/components/stack). Passing the `size` prop to this component will have effect on the descendants.
void',
description: `A function called when a new tab is selected`,
},
{
name: 'orientation',
type: '"horizontal" | "vertical"',
default: 'horizontal',
description: `The orientation the tabs are layed out`,
},
{
name: 'dir',
type: '"ltr" | "rtl"',
description: `The direction of navigation between toolbar items`,
},
{
name: 'activationMode',
type: '"manual" | "automatic"',
default: 'automatic',
description: `Whether or not a tab is activated automatically or manually. Not applicable on mobile`,
},
]}
/>
### Tabs.List
Container for the trigger buttons. Supports scrolling by extending [Group](/docs/components/group). You can disable passing border radius to children by passing `disablePassBorderRadius`.
### Tabs.Trigger
Extends [Button](/docs/components/button), adding:
void`,
description: `Used for making custom indicators when trigger interacted with`,
},
{
name: 'unstyled',
type: `boolean`,
description: `When true, remove all default tamagui styling`,
},
]}
/>
### Tabs.Content
Where each tab's content will be shown. Extends [ThemeableStack](/docs/components/stacks#themeablestack), adding:
## Examples
### Animations
Here is a demo with more advanced animations using [AnimatePresence](/docs/core/animations#animatepresence-and-exitstyle) and [Trigger](#trigger)'s `onInteraction` prop.
```tsx hero template=TabsAdvanced
```
## components/tabs/2.0.0
---
title: Tabs
description: Use in pages to manage sub-pages
name: tabs
component: Tabs
package: tabs
demoName: Tabs
---
StyledUnstyledHeadless
```tsx hero template=Tabs
````
```tsx hero template=TabsHeadless
````
```tsx hero template=TabsHeadless
````
## Installation
Tabs is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/tabs
````
Tabs is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/tabs
```
To use the headless tabs, import from the `@tamagui/tabs-headless` package. This package has no dependency on `@tamagui/core` and provides hooks for building custom tab interfaces with any styling solution.
```bash
npm install @tamagui/tabs-headless
```
## Usage
```tsx
import { SizableText, Tabs } from 'tamagui'
export default () => (
Tab 1Tab 2
Tab 1
Tab 2
)
```
Use the `createTabs` export to create fully custom tabs that still use the Tamagui styling system. You provide your own styled frame components and get back a fully functional tabs component.
```tsx template=TabsHeadless
```
The `useTabs` hook provides all the state and accessibility props needed to build custom tabs with any styling solution.
```tsx
import { useTabs } from '@tamagui/tabs-headless'
function MyTabs() {
const { tabsProps, listProps, getTabProps, getContentProps, value } = useTabs({
defaultValue: 'tab1',
orientation: 'horizontal',
})
return (
Tab 1Tab 2
{value === 'tab1' &&
Content 1
}
{value === 'tab2' &&
Content 2
}
)
}
```
### Component-Based API
For more complex use cases, you can use the context-based hooks:
```tsx
import { useTabs, TabsProvider, useTab, useTabContent } from '@tamagui/tabs-headless'
function Tabs({ children, ...props }) {
const { contextValue, tabsProps } = useTabs(props)
return (
{children}
)
}
function Tab({ value, children }) {
const { isSelected, tabProps } = useTab({ value })
return (
{children}
)
}
function TabContent({ value, children }) {
const { shouldMount, contentProps } = useTabContent({ value })
if (!shouldMount) return null
return
{children}
}
```
## API Reference
### Tabs
Root tabs component. Extends [Stack](/docs/components/stacks). Passing the `size` prop to this component will affect the descendants.
When using `createTabs`, you provide three styled components:
- `TabsFrame`: The root container component
- `TabFrame`: The tab trigger component
- `ContentFrame`: The content container component
The `useTabs` hook accepts these options and returns props/helpers:
void',
description: `A function called when a new tab is selected.`,
},
{
name: 'orientation',
type: '"horizontal" | "vertical"',
default: 'horizontal',
description: `The orientation the tabs are laid out in.`,
},
{
name: 'dir',
type: '"ltr" | "rtl"',
description: `The direction of navigation between toolbar items.`,
},
{
name: 'activationMode',
type: '"manual" | "automatic"',
default: 'manual',
description: `Whether a tab is activated automatically (on focus) or manually (on click/enter).`,
},
{
name: 'loop',
type: 'boolean',
default: 'true',
description: `Whether keyboard navigation should loop from last to first and vice versa.`,
},
]}
/>
### useTabs Return Value
| Property | Type | Description |
| ----------------- | ----------------------------------------------- | ------------------------------------- |
| `value` | `string` | The currently selected tab value |
| `setValue` | `(value: string) => void` | Function to change the selected tab |
| `direction` | `'ltr' \| 'rtl'` | The resolved text direction |
| `tabsProps` | `object` | Props to spread on the tabs container |
| `listProps` | `object` | Props to spread on the tab list |
| `getTabProps` | `(value: string, disabled?: boolean) => object` | Get props for a tab trigger |
| `getContentProps` | `(value: string) => object` | Get props for a tab content panel |
| `contextValue` | `TabsContextValue` | Context value for component-based API |
### useTab
Hook for individual tab triggers when using the component-based API.
```tsx
const { isSelected, tabProps } = useTab({
value: 'tab1',
disabled: false,
onPress: () => {},
onKeyDown: () => {},
onFocus: () => {},
})
```
### useTabContent
Hook for tab content panels when using the component-based API.
```tsx
const { isSelected, shouldMount, contentProps } = useTabContent({
value: 'tab1',
forceMount: false,
})
```
### Tabs.List
Container for the trigger buttons. Supports scrolling by extending [Group](/docs/components/group). You can disable passing border radius to children by passing `disablePassBorderRadius`.
Since Tabs.List extends Group, the same limitation applies: automatic border radius
detection only works when `Tabs.Tab` is a **direct child** of `Tabs.List`. If you wrap
tabs in custom components, see the [Group docs on nested
items](/docs/components/group#custom-components--nested-items) for workarounds.
### Tabs.Tab
Extends [ThemeableStack](/docs/components/stacks#themeablestack), adding:
void`,
description: `Used for making custom indicators when trigger is interacted with.`,
},
{
name: 'disabled',
type: `boolean`,
description: `Whether the tab is disabled.`,
},
{
name: 'unstyled',
type: `boolean`,
description: `When true, removes all default Tamagui styling.`,
},
{
name: 'activeStyle',
type: `StyleProp`,
description: `Styles to apply when the tab is selected.`,
},
{
name: 'activeTheme',
type: `string | null`,
description: `Theme to apply when the tab is selected. Set to null for no theme change.`,
},
]}
/>
### Tabs.Content
Where each tab's content will be shown. Extends [ThemeableStack](/docs/components/stacks#themeablestack), adding:
## Examples
### Animations
Here is a demo with more advanced animations using [AnimatePresence](/docs/core/animations#animatepresence-and-exitstyle) and [Tab](#tabstab)'s `onInteraction` prop.
```tsx hero template=TabsAdvanced
```
## components/tamagui-image/1.0.0
---
title: Image
description: Web compatible and super light image component with Tamagui style props.
name: html
component: Image
package: image-next
demoName: WebNativeImageDemo
---
```tsx hero template=WebNativeImage
```
## Installation
Image is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/image
```
## Usage
```tsx
export default () =>
```
## API Reference
### Image
[Tamagui props](/docs/intro/props) +
[Web img props](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img) +
[React Native Image props](https://necolas.github.io/react-native-web/docs/image/).
All web [img](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img) props are
supported on web, and all native
[Image](https://necolas.github.io/react-native-web/docs/image/) props are supported on
native. on native we are still using web img APIs, but not all web img props are
supported. like `decoding`
#### Some common props
## components/tamagui-image/2.0.0
---
title: Image
description: Web compatible and super light image component with Tamagui style props
name: tamagui-image
component: Image
package: image
demoName: WebNativeImageDemo
---
```tsx hero template=WebNativeImage
```
## Installation
Image is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/image
```
## Usage
```tsx
export default () =>
```
## API Reference
### Image
[Tamagui props](/docs/intro/props) +
[Web img props](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img) +
[React Native Image props](https://necolas.github.io/react-native-web/docs/image/).
All web [img](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img) props are
supported on web, and all native
[Image](https://necolas.github.io/react-native-web/docs/image/) props are supported on
native. On native we are still using web img APIs, but not all web img props are
supported, like `decoding`.
#### Some common props
## components/text/1.0.0-alpha
---
title: Text
description: Text, Sized Text and Paragraph show one way to build a design system.
name: text
component: Paragraph
demoName: Text
---
# Text
Text, Sized Text and Paragraph show one way to build a design system.
```tsx hero template=Text
```
### Usage
Text in Tamagui matches to Text in react-native-web, just with the added [Tamagui Props](/docs/intro/props).
It explicitly doesn't inherit your theme color or other font properties, as it's meant to be plain and used for extension. Below, we'll show `SizableText` which extends Text, and `Paragraph` which extends SizableText. Generally, Paragraph is the useful view as it will use theme values, while you can extend Text if you'd like to derive your own design system.
```tsx
import { Text, XStack, YStack } from 'tamagui'
export default () => (
<>
Lorem ipsum
>
)
```
SizableText and Paragraph default to the "body" fontFamily defined in your config.
Headings all default to "heading".
## SizableText
[Seeing how SizableText is defined](https://github.com/tamagui/tamagui/blob/v2/code/ui/text/src/SizableText.tsx) is helpful for understanding Tamagui. They serve as a good example of how you can extend and compose components.
SizableText simply adds a single `size` property to maniplulate all of:
- fontSize
- lineHeight
- fontWeight
- letterSpacing
Based on the values set in your tokens. It uses [spread variants](/docs/core/styled#spread-variants) feature. Then Paragraph extends that and ensures it defaults to values from your theme - fontSize, lineHeight, color and fontFamily.
## Paragraph
Finally Paragraph extends `SizableText` and simply sets some default values from your theme:
```tsx
export const Paragraph = styled(SizableText, {
fontFamily: '$body',
color: '$color',
// note tamagui uses a generic "true" token that your sizes should set to be the same as the default on your scale
size: '$true',
})
```
## components/text/1.0.0
---
title: Text
description: Text primitives with themes custom to each font.
name: text
component: Paragraph
package: text
demoName: Text
---
```tsx hero template=Text
```
## Installation
Text is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/text
```
## Usage
```tsx
export default () => (
<>
TextSizable TextParagraph
>
)
```
## Text
Text in Tamagui matches to Text in react-native-web, just with the added [Tamagui Props](/docs/intro/props).
It explicitly doesn't inherit your theme color or other font properties, as it's meant to be plain and used for extension. Below, we'll show `SizableText` which extends Text, and `Paragraph` which extends SizableText. Generally, Paragraph is the useful view as it will use theme values, while you can extend Text if you'd like to derive your own design system.
```tsx
import { Text, XStack, YStack } from 'tamagui'
export default () => (
<>
Lorem ipsum
>
)
```
## SizableText
Tamagui lets you define font sizing, spacing, line height, letter spacing and other properties with `createFont`, of which you can have many different configurations. We've found a nice pattern is to "align" all your keys across these sub-objects.
SizableText adds a `size` property thats defined using a [spread variant](/docs/core/styled#spread-variants) which looks for a matching key on each of these properties (using `@tamagui/get-font-sized`):
- color
- fontStyle
- textTransform
- fontFamily
- fontWeight
- letterSpacing
- fontSize
- lineHeight
So, if you've defined `small`, `medium` and `large` keys on each createFont category, you can use it like so:
```tsx
```
[Source code for SizableText](https://github.com/tamagui/tamagui/blob/main/code/ui/text/src/SizableText.tsx).
## Paragraph
Paragraph extends SizableText and is defined as:
```tsx
export const Paragraph = styled(SizableText, {
name: 'Paragraph',
tag: 'p',
userSelect: 'auto',
color: '$color',
size: '$true',
whiteSpace: 'normal',
})
```
Note: Paragraph renders to a `p` tag on web, which can cause issues when you nest them
during SSR. If you don't mind rendering to a span, use `SizableText`, otherwise, be
careful when nesting items inside a Paragraph.
## components/text/2.0.0
---
title: Text
description: Text primitives with themes custom to each font
name: text
component: Paragraph
package: text
demoName: Text
---
```tsx hero template=Text
```
The base `Text` component is already included in `@tamagui/core` (and `tamagui`). This
package is optional and adds `SizableText` and `Paragraph`, which extend `Text` with the
`size` prop and theme-aware defaults.
## Installation
If you're using `tamagui`, `SizableText` and `Paragraph` are already included. Otherwise, install independently:
```bash
npm install @tamagui/text
```
## Usage
```tsx
export default () => (
<>
TextSizable TextParagraph
>
)
```
## Text
Text in Tamagui matches Text in react-native-web, with the added [Tamagui props](/docs/intro/props).
It explicitly does not inherit your theme color or other font properties, as it is meant to be plain and used for extension. Below, we show `SizableText` which extends Text, and `Paragraph` which extends SizableText. Generally, Paragraph is the useful component as it uses theme values, while you can extend Text if you want to derive your own design system.
```tsx
import { Text, XStack, YStack } from 'tamagui'
export default () => (
<>
Lorem ipsum
>
)
```
## SizableText
Tamagui lets you define font sizing, spacing, line height, letter spacing and other properties with `createFont`, of which you can have many different configurations. We've found a nice pattern is to "align" all your keys across these sub-objects.
SizableText adds a `size` property that is defined using a [spread variant](/docs/core/styled#spread-variants) which looks for a matching key on each of these properties (using `@tamagui/get-font-sized`):
- color
- fontStyle
- textTransform
- fontFamily
- fontWeight
- letterSpacing
- fontSize
- lineHeight
So, if you've defined `small`, `medium` and `large` keys on each createFont category, you can use it like so:
```tsx
```
[Source code for SizableText](https://github.com/tamagui/tamagui/blob/main/code/ui/text/src/SizableText.tsx).
## Paragraph
Paragraph extends SizableText and is defined as:
```tsx
export const Paragraph = styled(SizableText, {
name: 'Paragraph',
tag: 'p',
userSelect: 'auto',
color: '$color',
size: '$true',
whiteSpace: 'normal',
})
```
Note: Paragraph renders to a `p` tag on web, which can cause issues when you nest them
during SSR. If you don't mind rendering to a span, use `SizableText`, otherwise, be
careful when nesting items inside a Paragraph.
## Inline Text Elements
For semantic inline text styling, `@tamagui/text` exports `Strong`, `Em`, and `Span`:
```tsx
import { Strong, Em, Span, Paragraph } from '@tamagui/text'
export default () => (
This is bold text, this is italic text, and this is a{' '}
colored span.
)
```
These render to their corresponding HTML elements (``, ``, ``) on web while remaining compatible with React Native.
## components/toast/1.11.3
---
title: Toast
description: A toast component with native features
name: toast
component: Toast
package: toast
demoName: Toast
---
# Toast Use to show feedback to user interactions
```tsx hero template=Toast
```
## Installation
Run the following command:
```
yarn add @tamagui/toast burnt
```
then, rebuild your React Native app. React Native requires sub-dependencies with native dependencies always be hoisted to your apps package.json and Toast relies on the amazing [Burnt](https://github.com/nandorojo/burnt) library by Fernando Rojo to provide its native functionality.
## Usage
To display the toast natively, you should either pass an array of native platforms (`native: ["ios", "web"]`), a single platform or `true` for all platforms.
```tsx
import { Button } from 'tamagui' // or '@tamagui/button'
import { Toast, ToastProvider, useToast } from '@tamagui/toast'
export default () => (
)
const CurrentToast = () => {
const { currentToast } = useToast()
// only show the component if it's present and not handled by native toast
if (!currentToast || currentToast.isHandledNatively) return null
return (
{currentToast.title}{currentToast.message}
)
}
const MyPage = () => {
const { show } = useToast()
return (
show('Done!', { message: 'Form submitted successfully.' })}>
Show Toast
)
}
```
## API
### ToastProvider
Your toasts should be wrapped within a `ToastProvider`. This is usually done at the root of your application.
`,
description: `Options for the burnt package if you're using native toasts on mobile`,
},
{
name: `notificationOptions`,
required: false,
type: `NotificationOptions`,
description: `Options for the notification API if you're using native toasts on web`,
},
]}
/>
### ToastViewport
The portal for toasts to be directed to. Should be used inside [ToastProvider](#toastprovider). Beyond [Stack Props](/docs/components/stacks/1.0.0), adds:
### Toast
Contains the Title, Description, Action and Close component. Should be used inside [ToastProvider](#toastprovider). Extends [Stack](/docs/components/stack#api) and adds:
#### Toast.Title
Should be used inside [Toast](#toast). Extends [SizableText](/docs/components/text/1.0.0#sizabletext).
#### Toast.Description
Should be used inside [Toast](#toast). Extends [SizableText](/docs/components/text/1.0.0#sizabletext).
#### Toast.Close
Should be used inside [Toast](#toast). Extends [Stack](/docs/components/stacks/1.0.0). You can pass `asChild` to this component and use a custom `` inside.
#### Toast.Action
Should be used inside [Toast](#toast). Extends [Stack](/docs/components/stacks/1.0.0). You can pass `asChild` to this component and use a custom `` inside.
### useToast
Should be used inside [ToastProvider](#toastprovider).
## FAQ
#### How to change the placement of toasts?
Native toasts:
- iOS (burnt): Supports top or bottom placements. Adjustable by passing `from` to `burntOptions`:
```tsx
```
- Android (burnt): Not supported.
- Web (Notification API): Not supported.
Non-native toasts:
You should change the positioning of your [``](#toastviewport). For instance, if you want them to appear from top right:
```tsx
```
Or for bottom center:
```tsx
```
When using multiple toasts, you can change the order of toasts by setting
`flexDirection` to `column` or `column-reverse`. Or even have them stack horizontally
using `row` or `row-reverse`.
#### How to show non-native toasts within safe area on mobile?
Install `react-native-safe-area-context` if you haven't, wrap your app inside ``, and use the safe area insets to position the viewport inside the safe area.
```tsx
import { useSafeAreaInsets } from 'react-native-safe-area-context'
const SafeToastViewport = () => {
const { left, top, right } = useSafeAreaInsets()
return (
)
}
```
#### Can I send toasts to different toast viewports?
Yes, but you will have to name them and then reference the viewport name on the `` component. for instance:
```tsx
const App = () => {
return (
{/* name will be "default" */}
)
}
const MyComponent = () => {
return {/* goes to default viewport */}
}
const MyComponent2 = () => {
return
}
```
#### How can I have more control over toasts?
You will have to opt-out of the native toasts and only use custom ones. Here are some examples:
##### Single Toast
```tsx
export default () => {
const [open, setOpen] = React.useState(false)
const timerRef = React.useRef(0)
React.useEffect(() => {
return () => clearTimeout(timerRef.current)
}, [])
return (
{
setOpen(false)
window.clearTimeout(timerRef.current)
timerRef.current = window.setTimeout(() => {
setOpen(true)
}, 150)
}}
>
Single Toast
Subscribed!We'll be in touch.
)
}
```
##### Multiple Toasts
To use multiple toasts, you should pass `multipleToasts` to your `ToastViewport`.
Otherwise there'll be issues when swipe-dismissing or animating toasts.
```tsx
export default () => {
const [savedCount, setSavedCount] = React.useState(0)
return (
{
setSavedCount((old) => old + 1)
}}
>
Show toast
{[...Array(savedCount)].map((_, index) => (
Subscribed!We'll be in touch.
))}
)
}
```
## components/toast/1.13.0
---
title: Toast
description: A toast component with native features
name: toast
component: Toast
package: toast
demoName: Toast
---
# Toast Use to show feedback to user interactions
```tsx hero template=Toast
```
## Installation
Run the following command:
```
yarn add @tamagui/toast burnt
```
then, if targetin native, rebuild your React Native app. React Native requires sub-dependencies with native dependencies always be hoisted to your apps package.json and Toast relies on the amazing [Burnt](https://github.com/nandorojo/burnt) library by Fernando Rojo to provide its native functionality.
## Usage
To display the toast natively, you should either pass an array of native platforms (`native: ["ios", "web"]`), a single platform or `true` for all platforms.
```tsx
import { Toast, ToastProvider, useToastController, useToastState } from '@tamagui/toast'
import { Button } from 'tamagui' // or '@tamagui/button'
export default () => (
)
const CurrentToast = () => {
const toast = useToastState()
// only show the component if it's present and not handled by native toast
if (!toast || toast.isHandledNatively) {
return null
}
return (
{toast.title}{toast.message}
)
}
const MyPage = () => {
const { show } = useToastController()
return (
show('Done!', { message: 'Form submitted successfully.' })}>
Show Toast
)
}
```
## API
### ToastProvider
Your toasts should be wrapped within a `ToastProvider`. This is usually done at the root of your application.
`,
description: `Options for the burnt package if you're using native toasts on mobile`,
},
{
name: `notificationOptions`,
required: false,
type: `NotificationOptions`,
description: `Options for the notification API if you're using native toasts on web`,
},
]}
/>
### ToastViewport
The portal for toasts to be directed to. Should be used inside [ToastProvider](#toastprovider). Beyond [Stack Props](/docs/components/stacks/1.0.0), adds:
### Toast
Contains the Title, Description, Action and Close component. Should be used inside [ToastProvider](#toastprovider). Extends [Stack](/docs/components/stack#api) and adds:
#### Toast.Title
Should be used inside [Toast](#toast). Extends [SizableText](/docs/components/text/1.0.0#sizabletext).
#### Toast.Description
Should be used inside [Toast](#toast). Extends [SizableText](/docs/components/text/1.0.0#sizabletext).
#### Toast.Close
Should be used inside [Toast](#toast). Extends [Stack](/docs/components/stacks/1.0.0). You can pass `asChild` to this component and use a custom `` inside.
#### Toast.Action
Should be used inside [Toast](#toast). Extends [Stack](/docs/components/stacks/1.0.0). You can pass `asChild` to this component and use a custom `` inside.
### useToastController
Used to control the display of toasts. Should be used inside [ToastProvider](#toastprovider).
### useToastState
Used to render out your toast contents. Should be used inside [ToastProvider](#toastprovider).
## FAQ
#### How to change the placement of toasts?
Native toasts:
- iOS (burnt): Supports top or bottom placements. Adjustable by passing `from` to `burntOptions`:
```tsx
```
- Android (burnt): Not supported.
- Web (Notification API): Not supported.
Non-native toasts:
You should change the positioning of your [``](#toastviewport). For instance, if you want them to appear from top right:
```tsx
```
Or for bottom center:
```tsx
```
When using multiple toasts, you can change the order of toasts by setting
`flexDirection` to `column` or `column-reverse`. Or even have them stack horizontally
using `row` or `row-reverse`.
#### How to show non-native toasts within safe area on mobile?
Install `react-native-safe-area-context` if you haven't, wrap your app inside ``, and use the safe area insets to position the viewport inside the safe area.
```tsx
import { useSafeAreaInsets } from 'react-native-safe-area-context'
const SafeToastViewport = () => {
const { left, top, right } = useSafeAreaInsets()
return (
)
}
```
#### Can I send toasts to different toast viewports?
Yes, but you will have to name them and then reference the viewport name on the `` component. for instance:
```tsx
const App = () => {
return (
{/* name will be "default" */}
)
}
const MyComponent = () => {
return {/* goes to default viewport */}
}
const MyComponent2 = () => {
return
}
```
#### How can I have more control over toasts?
You will have to opt-out of the native toasts and only use custom ones. Here are some examples:
##### Single Toast
```tsx
export default () => {
const [open, setOpen] = React.useState(false)
const timerRef = React.useRef(0)
React.useEffect(() => {
return () => clearTimeout(timerRef.current)
}, [])
return (
{
setOpen(false)
window.clearTimeout(timerRef.current)
timerRef.current = window.setTimeout(() => {
setOpen(true)
}, 150)
}}
>
Single Toast
Subscribed!We'll be in touch.
)
}
```
##### Multiple Toasts
To use multiple toasts, you should pass `multipleToasts` to your `ToastViewport`.
Otherwise there'll be issues when swipe-dismissing or animating toasts.
```tsx
export default () => {
const [savedCount, setSavedCount] = React.useState(0)
return (
{
setSavedCount((old) => old + 1)
}}
>
Show toast
{[...Array(savedCount)].map((_, index) => (
Subscribed!We'll be in touch.
))}
)
}
```
## components/toast/1.15.15
---
title: Toast
description: A toast component with native features
name: toast
component: Toast
package: toast
demoName: Toast
---
# Toast Use to show feedback to user interactions
```tsx hero template=Toast
```
## Installation
Run the following command:
```bash
yarn add @tamagui/toast burnt
```
Then, if targeting native, rebuild your React Native app. React Native requires sub-dependencies with native dependencies always be hoisted to your apps package.json and Toast relies on the amazing [Burnt](https://github.com/nandorojo/burnt) library by Fernando Rojo to provide its native functionality.
## Anatomy
```tsx
```
## API Reference
### ToastProvider
Your toasts should be wrapped within a `ToastProvider`. This is usually done at the root of your application.
`,
description: `Options for the burnt package if you're using native toasts on mobile`,
},
{
name: `notificationOptions`,
required: false,
type: `NotificationOptions`,
description: `Options for the notification API if you're using native toasts on web`,
},
]}
/>
### ToastViewport
The portal for toasts to be directed to. Should be used inside [ToastProvider](#toastprovider). Beyond [Stack Props](/docs/components/stacks/1.0.0), adds:
### Toast
Contains the Title, Description, Action and Close component. Should be used inside [ToastProvider](#toastprovider). Extends [Stack](/docs/components/stack#api) and adds:
### Toast.Title
Should be used inside [Toast](#toast). Extends [SizableText](/docs/components/text/1.0.0#sizabletext), adding:
### Toast.Description
Should be used inside [Toast](#toast). Extends [SizableText](/docs/components/text/1.0.0#sizabletext), adding:
### Toast.Close
Should be used inside [Toast](#toast). Extends [Stack](/docs/components/stacks/1.0.0). You can pass `asChild` to this component and use a custom `` inside.
### Toast.Action
Should be used inside [Toast](#toast). Extends [Stack](/docs/components/stacks/1.0.0). You can pass `asChild` to this component and use a custom `` inside.
### useToastController
Used to control the display of toasts. Should be used inside [ToastProvider](#toastprovider).
### useToastState
Used to render out your toast contents. Should be used inside [ToastProvider](#toastprovider). Doesn't take in anything and returns `ToastData`.
```tsx
const CurrentToast = () => {
const toast = useToastState()
// don't show any toast if no toast is present or it's handled natively
if (!toast || toast.isHandledNatively) {
return null
}
return (
{toast.title}{toast.message}
)
}
```
## Examples
### Position the viewport
To position the viewport on native toasts:
- iOS (burnt): Supports top or bottom placements. Adjustable by passing `from` to `burntOptions`:
```tsx
```
- Android (burnt): Not supported.
- Web (Notification API): Not supported.
To position the viewport on custom toasts:
You should change the positioning of your [``](#toastviewport). For instance, if you want them to appear from top right:
```tsx
```
Or for bottom center:
```tsx
```
When using multiple toasts, you can change the order of toasts by setting
`flexDirection` to `column` or `column-reverse`. Or even have them stack horizontally
using `row` or `row-reverse`.
### Mobile safe area
To show toasts inside device's safe area, install `react-native-safe-area-context` if you haven't, wrap your app inside ``, and then use the safe area insets to position the viewport inside the safe area.
```tsx
import { useSafeAreaInsets } from 'react-native-safe-area-context'
const SafeToastViewport = () => {
const { left, top, right } = useSafeAreaInsets()
return (
)
}
```
### Different viewports
To send toasts to different viewports, you can set up different viewports:
```tsx
const App = () => {
return (
{/* default viewport */}
)
}
```
And then, use the viewport's name on the toasts.
```tsx
const MyComponent = () => {
return // default viewport
}
const MyComponent2 = () => {
return
}
```
### Custom data
Just pass your custom data to the second parameter of the `show()` method.
```ts
const toastController = useToastController()
toastController.show('Title', { myPreset: 'error' }) // or toastController.show("Title", { customData: { myPreset: 'error' } })
```
then, when showing the toast, you can retrieve them like so:
```ts
const toastState = useToastState()
toastState.myPreset // or toastState.customData.myPreset
```
To add TypeScript auto-completion for your custom fields, you can use TS module augmentation:
```ts
declare module '@tamagui/toast' {
interface CustomData {
myPreset: 'error' | 'success' | 'warning'
}
}
```
### Without hooks
You can also use toasts without the hooks.
You can't use native toasts this way.
#### Single Toast
```tsx
export default () => {
const [open, setOpen] = React.useState(false)
const timerRef = React.useRef(0)
React.useEffect(() => {
return () => clearTimeout(timerRef.current)
}, [])
return (
{
setOpen(false)
window.clearTimeout(timerRef.current)
timerRef.current = window.setTimeout(() => {
setOpen(true)
}, 150)
}}
>
Single Toast
Subscribed!We'll be in touch.
)
}
```
#### Multiple Toasts
To use multiple toasts, you should pass `multipleToasts` to your `ToastViewport`.
Otherwise there'll be issues when swipe-dismissing or animating toasts.
```tsx
export default () => {
const [savedCount, setSavedCount] = React.useState(0)
return (
{
setSavedCount((old) => old + 1)
}}
>
Show toast
{[...Array(savedCount)].map((_, index) => (
Subscribed!We'll be in touch.
))}
)
}
```
## components/toast/1.8.0
---
title: Toast
description: A toast component with native features
name: toast
component: Toast
package: toast
demoName: Toast
---
# Toast Use to show feedback to user interactions
```tsx hero template=Toast
```
## Install
For native support, run `yarn add burnt` to add `burnt`, then rebuild your React Native app. React Native requires sub-dependencies with native dependencies always be hoisted to your apps package.json and Toast relies on the amazing [Burnt](https://github.com/nandorojo/burnt) library by Fernando Rojo to provide its native functionality.
## Anatomy
```tsx
import { Toast, ToastProvider, ToastViewport } from 'tamagui' // or '@tamagui/toast'
export default () => (
)
```
## Usage
### Single Toast
```tsx
export default () => {
const [open, setOpen] = React.useState(false)
const timerRef = React.useRef(0)
React.useEffect(() => {
return () => clearTimeout(timerRef.current)
}, [])
return (
{
setOpen(false)
window.clearTimeout(timerRef.current)
timerRef.current = window.setTimeout(() => {
setOpen(true)
}, 150)
}}
>
Single Toast
Subscribed!We'll be in touch.
)
}
```
### Duplicate Toasts
```tsx
export default () => {
const [savedCount, setSavedCount] = React.useState(0)
return (
{
setSavedCount((old) => old + 1)
}}
>
Show toast
{[...Array(savedCount)].map((_, index) => (
Subscribed!We'll be in touch.
))}
)
}
```
### Using `createToast`
```tsx
import { Button } from 'tamagui' // or '@tamagui/button'
import { Toast, ToastProvider, createToast } from 'tamagui' // or '@tamagui/toast'
export const { ImperativeToastProvider, useToast } = createToast()
export default () => (
)
const CurrentToast = () => {
const { currentToast } = useToast()
if (!currentToast) return
return (
{currentToast.title}{currentToast.message}
)
}
const MyPage = () => {
const { show } = useToast()
return (
show('Done!', { message: 'Form submitted successfully.' })}>
Show Toast
)
}
```
## API
### ToastProvider
Your toasts should be wrapped within a `ToastProvider`. This is usually done at the root of your application.
### ToastViewport
The portal for toasts to be directed to. Should be inside [ToastProvider](#toastprovider). Beyond [Stack Props](/docs/components/stacks/1.0.0), adds:
### Toast
Contains the Title, Description, Action and Close component. Should be inside [ToastProvider](#toastprovider). Extends [Stack](/docs/components/stack#api) and adds:
#### Toast.Title
Should be inside [Toast](#toast). Extends [SizableText](/docs/components/text/1.0.0#sizabletext).
#### Toast.Description
Should be inside [Toast](#toast). Extends [SizableText](/docs/components/text/1.0.0#sizabletext).
#### Toast.Close
Should be inside [Toast](#toast). Extends [Stack](/docs/components/stacks/1.0.0). You can pass `asChild` to this component and use a custom `` inside.
#### Toast.Action
Should be inside [Toast](#toast). Extends [Stack](/docs/components/stacks/1.0.0). You can pass `asChild` to this component and use a custom `` inside.
### createToast
An alternative way to work with toasts.
This function, then returns the following:
#### ImperativeToastProvider
Wrap children within this provider so that they can use `useToast()`. Takes no params.
#### useToast
You may export this hook to use it throughout your app.
## components/toast/1.83.0
---
title: Toast
description: Use to show feedback to user interactions.
name: toast
component: Toast
package: toast
demoName: Toast
---
```tsx hero template=Toast
```
## Installation
Note that `@tamagui/toast` is the only UI package not included by default in `tamagui`. The reason for this is that Metro would force you to install the native `burnt` dependency, and that would mean `tamagui` wouldn't work with Expo Go and would require a native install step no matter if you used Toast or not. This is due to a limitation in Metro.
To install toast:
```bash
yarn add @tamagui/toast burnt
```
Then, if targeting native, rebuild your React Native app. React Native requires sub-dependencies with native dependencies always be hoisted to your apps package.json and Toast relies on the amazing [Burnt](https://github.com/nandorojo/burnt) library by Fernando Rojo to provide its native functionality.
We're open to a refactor that moves the burnt dependency into a sub-path like `@tamagui/toast/burnt` and forces setup through there, that likely fixes the Metro issue and allow us to include it by default.
## Anatomy
```tsx
```
## API Reference
### ToastProvider
Your toasts should be wrapped within a `ToastProvider`. This is usually done at the root of your application.
`,
description: `Options for the burnt package if you're using native toasts on mobile`,
},
{
name: `notificationOptions`,
required: false,
type: `NotificationOptions`,
description: `Options for the notification API if you're using native toasts on web`,
},
]}
/>
### ToastViewport
The portal for toasts to be directed to. Should be used inside [ToastProvider](#toastprovider). Beyond [Stack Props](/docs/components/stacks), adds:
### Toast
Contains the Title, Description, Action and Close component. Should be used inside [ToastProvider](#toastprovider). Extends [Stack](/docs/components/stacks) and adds:
### Toast.Title
Should be used inside [Toast](#toast). Extends [SizableText](/docs/components/text#sizabletext), adding:
### Toast.Description
Should be used inside [Toast](#toast). Extends [SizableText](/docs/components/text#sizabletext), adding:
### Toast.Close
Should be used inside [Toast](#toast). Extends [Stack](/docs/components/stacks). You can pass `asChild` to this component and use a custom `` inside.
### Toast.Action
Should be used inside [Toast](#toast). Extends [Stack](/docs/components/stacks). You can pass `asChild` to this component and use a custom `` inside.
### useToastController
Used to control the display of toasts. Should be used inside [ToastProvider](#toastprovider).
### useToastState
Used to render out your toast contents. Should be used inside [ToastProvider](#toastprovider). Doesn't take in anything and returns `ToastData`.
```tsx
const CurrentToast = () => {
const toast = useToastState()
// don't show any toast if no toast is present or it's handled natively
if (!toast || toast.isHandledNatively) {
return null
}
return (
{toast.title}{toast.message}
)
}
```
## Examples
### Position the viewport
To position the viewport on native toasts:
- iOS (burnt): Supports top or bottom placements. Adjustable by passing `from` to `burntOptions`:
```tsx
```
- Android (burnt): Not supported.
- Web (Notification API): Not supported.
To position the viewport on custom toasts:
You should change the positioning of your [``](#toastviewport). For instance, if you want them to appear from top right:
```tsx
```
Or for bottom center:
```tsx
```
When using multiple toasts, you can change the order of toasts by setting
`flexDirection` to `column` or `column-reverse`. Or even have them stack horizontally
using `row` or `row-reverse`.
### Mobile safe area
To show toasts inside device's safe area, install `react-native-safe-area-context` if you haven't, wrap your app inside ``, and then use the safe area insets to position the viewport inside the safe area.
```tsx
import { useSafeAreaInsets } from 'react-native-safe-area-context'
const SafeToastViewport = () => {
const { left, top, right } = useSafeAreaInsets()
return (
)
}
```
### Different viewports
To send toasts to different viewports, you can set up different viewports:
```tsx
const App = () => {
return (
{/* default viewport */}
)
}
```
And then, use the viewport's name on the toasts.
```tsx
const MyComponent = () => {
return // default viewport
}
const MyComponent2 = () => {
return
}
```
### Custom data
Just pass your custom data to the second parameter of the `show()` method.
```ts
const toastController = useToastController()
toastController.show('Title', { myPreset: 'error' }) // or toastController.show("Title", { customData: { myPreset: 'error' } })
```
then, when showing the toast, you can retrieve them like so:
```ts
const toastState = useToastState()
toastState.myPreset // or toastState.customData.myPreset
```
To add TypeScript auto-completion for your custom fields, you can use TS module augmentation:
```ts
declare module '@tamagui/toast' {
interface CustomData {
myPreset: 'error' | 'success' | 'warning'
}
}
```
### Without hooks
You can also use toasts without the hooks.
You can't use native toasts this way.
#### Single Toast
```tsx
export default () => {
const [open, setOpen] = React.useState(false)
const timerRef = React.useRef(0)
React.useEffect(() => {
return () => clearTimeout(timerRef.current)
}, [])
return (
{
setOpen(false)
window.clearTimeout(timerRef.current)
timerRef.current = window.setTimeout(() => {
setOpen(true)
}, 150)
}}
>
Single Toast
Subscribed!We'll be in touch.
)
}
```
#### Multiple Toasts
To use multiple toasts, you should pass `multipleToasts` to your `ToastViewport`.
Otherwise there'll be issues when swipe-dismissing or animating toasts.
```tsx
export default () => {
const [savedCount, setSavedCount] = React.useState(0)
return (
{
setSavedCount((old) => old + 1)
}}
>
Show toast
{[...Array(savedCount)].map((_, index) => (
Subscribed!We'll be in touch.
))}
)
}
```
## components/toast/1.9.1
---
title: Toast
description: A toast component with native features
name: toast
component: Toast
package: toast
demoName: Toast
---
# Toast Use to show feedback to user interactions
```tsx hero template=Toast
```
## Usage
### Imperative API
This API offers a nice imperative interface, support for native toasts with a lot of control.
#### Installation
For native support on mobile, run `yarn add burnt` to add `burnt`, then rebuild your React Native app. React Native requires sub-dependencies with native dependencies always be hoisted to your apps package.json and Toast relies on the amazing [Burnt](https://github.com/nandorojo/burnt) library by Fernando Rojo to provide its native functionality.
Note: `Burnt` [will not work](https://github.com/nandorojo/burnt?tab=readme-ov-file#expo) with Expo Go.
#### Usage
To display the toast natively, you should either pass an array of native platforms (`native: ["ios", "web"]`), a single platform or `true` for all platforms.
```tsx
import { Button } from 'tamagui' // or '@tamagui/button'
import { Toast, ToastImperativeProvider, ToastProvider, useToast } from 'tamagui' // or '@tamagui/toast'
const options = { native: 'mobile' }
export default () => (
)
const CurrentToast = () => {
const { currentToast } = useToast()
// only show the component if it's present and not handled by native toast
if (!currentToast || currentToast.isHandledNatively) return null
return (
{currentToast.title}{currentToast.message}
)
}
const MyPage = () => {
const { show } = useToast()
return (
show('Done!', { message: 'Form submitted successfully.' })}>
Show Toast
)
}
```
### Barebone API
This API does not support native toasts. For native toasts, use the [Imperative
API](#imperative-api).
#### Single Toast
```tsx
export default () => {
const [open, setOpen] = React.useState(false)
const timerRef = React.useRef(0)
React.useEffect(() => {
return () => clearTimeout(timerRef.current)
}, [])
return (
{
setOpen(false)
window.clearTimeout(timerRef.current)
timerRef.current = window.setTimeout(() => {
setOpen(true)
}, 150)
}}
>
Single Toast
Subscribed!We'll be in touch.
)
}
```
#### Multiple Toast
To use multiple toasts, you should pass `multipleToasts` to your `ToastViewport`.
Otherwise there'll be issues when swipe-dismissing or animating toasts.
```tsx
export default () => {
const [savedCount, setSavedCount] = React.useState(0)
return (
{
setSavedCount((old) => old + 1)
}}
>
Show toast
{[...Array(savedCount)].map((_, index) => (
Subscribed!We'll be in touch.
))}
)
}
```
## API
### ToastProvider
Your toasts should be wrapped within a `ToastProvider`. This is usually done at the root of your application.
### ToastViewport
The portal for toasts to be directed to. Should be inside [ToastProvider](#toastprovider). Beyond [Stack Props](/docs/components/stacks/1.0.0), adds:
### Toast
Contains the Title, Description, Action and Close component. Should be inside [ToastProvider](#toastprovider). Extends [Stack](/docs/components/stack#api) and adds:
#### Toast.Title
Should be inside [Toast](#toast). Extends [SizableText](/docs/components/text/1.0.0#sizabletext).
#### Toast.Description
Should be inside [Toast](#toast). Extends [SizableText](/docs/components/text/1.0.0#sizabletext).
#### Toast.Close
Should be inside [Toast](#toast). Extends [Stack](/docs/components/stacks/1.0.0). You can pass `asChild` to this component and use a custom `` inside.
#### Toast.Action
Should be inside [Toast](#toast). Extends [Stack](/docs/components/stacks/1.0.0). You can pass `asChild` to this component and use a custom `` inside.
### ToastImperativeProvider
Wrap components within this provider to use `useToast()` inside them.
### useToast
Used when using the imperative API.
## FAQ
#### How to change the placement of toasts?
##### Native toasts
- iOS (burnt): Supports top or bottom placements. Adjustable by passing `from` to `burntOptions`:
```tsx
```
- Android (burnt): Not supported.
- Web (Notification API): Not supported.
##### Non-native toasts
You should change the positioning of your [``](#toastviewport). For instance, if you want them to appear from top right:
```tsx
```
Or for bottom center:
```tsx
```
When using multiple toasts, you can change the order of toasts by setting
`flexDirection` to `column` or `column-reverse`. Or even have them stack horizontally
using `row` or `row-reverse`.
#### How to show non-native toasts within safe area on mobile?
Install `react-native-safe-area-context` if you haven't, wrap your app inside ``, and use the safe area insets to position the viewport inside the safe area.
```tsx
import { useSafeAreaInsets } from 'react-native-safe-area-context'
const SafeToastViewport = () => {
const { left, top, right } = useSafeAreaInsets()
return (
)
}
```
#### Can I have multiple viewports?
Yes, but you will have to name them and then reference the viewport name on the `` component. for instance:
```tsx
const App = () => {
return (
// name will be "default"
)
}
const MyComponent = () => {
return // goes to default viewport // ...
}
const MyComponent2 = () => {
return // ...
}
```
## components/toast/2.0.0
---
title: Toast
description: Use to show feedback to user interactions.
name: toast
component: Toast
package: toast
demoName: Toast
---
```tsx hero template=Toast
```
## Installation
Toast is included by default in `tamagui`. If you're using it standalone:
```bash
yarn add @tamagui/toast
```
### Native Toast Setup
For native toasts on iOS/Android (using [Burnt](https://github.com/nandorojo/burnt) by Fernando Rojo), install the native dependency and import the setup module:
```bash
yarn add burnt
```
```tsx
// App.tsx - before any Tamagui imports
import '@tamagui/native/setup-burnt'
```
Then rebuild your React Native app. Without this setup, toasts will still work but the `native` prop will have no effect on mobile.
## Anatomy
```tsx
```
## API Reference
### ToastProvider
Your toasts should be wrapped within a `ToastProvider`. This is usually done at the root of your application.
`,
description: `Options for the burnt package if you're using native toasts on mobile`,
},
{
name: `notificationOptions`,
required: false,
type: `NotificationOptions`,
description: `Options for the notification API if you're using native toasts on web`,
},
]}
/>
### ToastViewport
The portal for toasts to be directed to. Should be used inside [ToastProvider](#toastprovider). Beyond [Stack Props](/docs/components/stacks), adds:
### Toast
Contains the Title, Description, Action and Close component. Should be used inside [ToastProvider](#toastprovider). Extends [Stack](/docs/components/stacks) and adds:
### Toast.Title
Should be used inside [Toast](#toast). Extends [SizableText](/docs/components/text#sizabletext), adding:
### Toast.Description
Should be used inside [Toast](#toast). Extends [SizableText](/docs/components/text#sizabletext), adding:
### Toast.Close
Should be used inside [Toast](#toast). Extends [Stack](/docs/components/stacks). You can pass `asChild` to this component and use a custom `` inside.
### Toast.Action
Should be used inside [Toast](#toast). Extends [Stack](/docs/components/stacks). You can pass `asChild` to this component and use a custom `` inside.
### useToastController
Used to control the display of toasts. Should be used inside [ToastProvider](#toastprovider).
### useToastState
Used to render out your toast contents. Should be used inside [ToastProvider](#toastprovider). Doesn't take in anything and returns `ToastData`.
```tsx
const CurrentToast = () => {
const toast = useToastState()
// don't show any toast if no toast is present or it's handled natively
if (!toast || toast.isHandledNatively) {
return null
}
return (
{toast.title}{toast.message}
)
}
```
## Examples
### Position the viewport
To position the viewport on native toasts:
- iOS (burnt): Supports top or bottom placements. Adjustable by passing `from` to `burntOptions`:
```tsx
```
- Android (burnt): Not supported.
- Web (Notification API): Not supported.
To position the viewport on custom toasts:
You should change the positioning of your [``](#toastviewport). For instance, if you want them to appear from top right:
```tsx
```
Or for bottom center:
```tsx
```
When using multiple toasts, you can change the order of toasts by setting
`flexDirection` to `column` or `column-reverse`. Or even have them stack horizontally
using `row` or `row-reverse`.
### Mobile safe area
To show toasts inside device's safe area, install `react-native-safe-area-context` if you haven't, wrap your app inside ``, and then use the safe area insets to position the viewport inside the safe area.
```tsx
import { useSafeAreaInsets } from 'react-native-safe-area-context'
const SafeToastViewport = () => {
const { left, top, right } = useSafeAreaInsets()
return (
)
}
```
### Different viewports
To send toasts to different viewports, you can set up different viewports:
```tsx
const App = () => {
return (
{/* default viewport */}
)
}
```
And then, use the viewport's name on the toasts.
```tsx
const MyComponent = () => {
return // default viewport
}
const MyComponent2 = () => {
return
}
```
### Custom data
Just pass your custom data to the second parameter of the `show()` method.
```ts
const toastController = useToastController()
toastController.show('Title', { myPreset: 'error' }) // or toastController.show("Title", { customData: { myPreset: 'error' } })
```
then, when showing the toast, you can retrieve them like so:
```ts
const toastState = useToastState()
toastState.myPreset // or toastState.customData.myPreset
```
To add TypeScript auto-completion for your custom fields, you can use TS module augmentation:
```ts
declare module '@tamagui/toast' {
interface CustomData {
myPreset: 'error' | 'success' | 'warning'
}
}
```
### Without hooks
You can also use toasts without the hooks.
You can't use native toasts this way.
#### Single Toast
```tsx
export default () => {
const [open, setOpen] = React.useState(false)
const timerRef = React.useRef(0)
React.useEffect(() => {
return () => clearTimeout(timerRef.current)
}, [])
return (
{
setOpen(false)
window.clearTimeout(timerRef.current)
timerRef.current = window.setTimeout(() => {
setOpen(true)
}, 150)
}}
>
Single Toast
Subscribed!We'll be in touch.
)
}
```
#### Multiple Toasts
To use multiple toasts, you should pass `multipleToasts` to your `ToastViewport`.
Otherwise there'll be issues when swipe-dismissing or animating toasts.
```tsx
export default () => {
const [savedCount, setSavedCount] = React.useState(0)
return (
{
setSavedCount((old) => old + 1)
}}
>
Show toast
{[...Array(savedCount)].map((_, index) => (
Subscribed!We'll be in touch.
))}
)
}
```
## components/toggle-group/1.10.0
---
title: ToggleGroup
description: Two-state buttons that can be toggled on or off.
name: toggleGroup
component: ToggleGroup
package: toggle-group
demoName: ToggleGroup
---
```tsx hero template=ToggleGroup
```
## Installation
ToggleGroup is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/toggle-group
```
## Usage
```tsx
import { ToggleGroup } from 'tamagui'
export default () => {
return (
)
}
```
## API Reference
### ToggleGroup
`ToggleGroup` extends the [Group](/docs/components/group) component. You can disable passing border radius to children by passing `disablePassBorderRadius`. plus:
void',
description: `Event handler called when the pressed state of an item changes and type is "multiple".`,
},
{
name: 'loop',
type: 'boolean',
description: `Whether or not to loop over after reaching the end or start of the items. Used mainly for managing keyboard navigation.`,
default: `true`,
},
{
name: 'disableDeactivation',
type: 'boolean',
description: `Won't let the user turn the active item off. Only applied to single toggle group.`,
default: 'false',
},
{
name: 'unstyled',
type: 'boolean',
default: 'false',
description: `When true, remove all default tamagui styling.`,
},
{
name: 'sizeAdjust',
type: 'number',
description: `Adjust the component's size scaling by this number.`,
},
]}
/>
### ToggleGroup.Item
`ToggleGroup.Item` extend Stack views inheriting all the [Tamagui standard props](notion://www.notion.so/docs/intro/props), plus:
When it is active, it will receive an `active` prop set to true. This means you can customize the active styles like so:
```tsx
import { ToggleGroup } from '@tamagui/toggle-group'
import { styled } from 'tamagui'
const MyToggleGroupItem = styled(ToggleGroup.Item, {
variants: {
active: {
true: {
backgroundColor: 'red',
},
},
},
})
```
## components/toggle-group/2.0.0
---
title: ToggleGroup
description: Two-state buttons that can be toggled on or off
name: toggleGroup
component: ToggleGroup
package: toggle-group
demoName: ToggleGroup
---
```tsx hero template=ToggleGroup
```
## Installation
ToggleGroup is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/toggle-group
```
## Usage
ToggleGroup handles the toggle state logic. For visual grouping with border radius, compose with `XGroup` or `YGroup`. Use `activeStyle` to customize the active state appearance:
```tsx
import { ToggleGroup, XGroup } from 'tamagui'
export default () => {
return (
Foo
Bar
)
}
```
For vertical layouts, use `YGroup`:
```tsx
Top
Bottom
```
## API Reference
### ToggleGroup
ToggleGroup manages toggle state and keyboard navigation. It does not render any visible element by default - use `XGroup`/`YGroup` for visual grouping.
void',
description: `Event handler called when the pressed state of an item changes.`,
},
{
name: 'loop',
type: 'boolean',
description: `Whether or not to loop over after reaching the end or start of the items. Used for keyboard navigation.`,
default: `true`,
},
{
name: 'disableDeactivation',
type: 'boolean',
description: `Won't let the user turn the active item off. Only applies to type="single".`,
default: 'false',
},
{
name: 'rovingFocus',
type: 'boolean',
description: `Enable roving focus keyboard navigation between items.`,
default: 'true',
},
]}
/>
### ToggleGroup.Item
`ToggleGroup.Item` extends Stack views inheriting all the [Tamagui standard props](/docs/intro/props), plus:
### Styling Active State
Customize the active/pressed state using `activeStyle`:
```tsx
// Inline usage
;
Left
// Or via styled()
const GreenItem = styled(ToggleGroup.Item, {
activeStyle: {
backgroundColor: '$green9',
color: '$yellow9',
},
})
```
You can also use `activeTheme` to apply a theme when active:
```tsx
Option 1
```
### useToggleGroupItem
For custom components inside `ToggleGroup.Item` that need to know the active state, use the `useToggleGroupItem` hook:
```tsx
import { useToggleGroupItem, ToggleGroup } from '@tamagui/toggle-group'
function CustomLabel({ children }) {
const { active, color } = useToggleGroupItem()
return {children}
}
// Usage
;Option 1
```
## components/tooltip/1.0.0
---
title: Tooltip
description: A simple tooltip component
name: tooltip
component: Tooltip
package: tooltip
demoName: Tooltip
---
# Tooltip
A tooltip on web, with only accessibility output on native
```tsx hero template=Tooltip
```
Note that Tooltip doesn't render on native platforms.
## Installation
Tooltip is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/tooltip
```
### PortalProvider
When rendering into root of app instead of inline, you'll first need to install the `@tamagui/portal` package:
```bash
npm install @tamagui/portal
```
Then add `PortalProvider` to the root of your app:
```tsx fileName="App.tsx"
import { PortalProvider } from '@tamagui/portal'
import YourApp from './components/YourApp'
function App() {
return (
)
}
export default App
```
## Anatomy
```tsx
import { Tooltip } from 'tamagui' // or '@tamagui/tooltip'
export default () => (
{/* ... */}
)
```
## API Reference
### Tooltip
Contains every component for the tooltip.
void',
required: false,
},
{
name: 'modal',
type: 'boolean',
default: 'true',
required: false,
description: `Renders into root of app instead of inline`,
},
{
name: 'stayInFrame',
type: 'ShiftProps',
required: false,
description: `See floating-ui shift()`,
},
{
name: 'allowFlip',
type: 'FlipProps',
required: false,
description: `See floating-ui flip`,
},
{
name: 'offset',
type: 'OffsetOptions',
required: false,
description: `Determines the distance the Popover appears from the target, see floating-ui offset().`,
},
]}
/>
If using `modal={true}` (which is `true` by default), refer to the [PortalProvider
installation](/ui/tooltip/1.0.0#portalprovider) for more information.
### Tooltip.Trigger
Used to trigger opening of the popover when uncontrolled, see YStack in [Stacks](/docs/components/stacks).
### Tooltip.Content
Renders as SizableStack (see [Stacks](/docs/components/stacks)) with an extra `size` prop that accepts any `SizeTokens`.
### Tooltip.Anchor
Renders as YStack, see [Stacks](/docs/components/stacks).
When you want the Trigger to be in another location from where the Tooltip attaches, use Anchor. When used, Anchor is where the Tooltip will attach, while Trigger will open it.
## components/tooltip/1.105.0
---
title: Tooltip
description: A simple tooltip component
name: tooltip
component: Tooltip
package: tooltip
demoName: Tooltip
---
# Tooltip
A tooltip on web, with only accessibility output on native
```tsx hero template=Tooltip
```
Note that Tooltip doesn't render on native platforms.
## Installation
Tooltip is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/tooltip
```
### PortalProvider
Only if you aren't not using `tamagui` (but rather `@tamagui/core`) you'll need to install the `@tamagui/portal` package:
```bash
npm install @tamagui/portal
```
Then add `PortalProvider` to the root of your app:
```tsx fileName="App.tsx"
import { PortalProvider } from '@tamagui/portal'
import YourApp from './components/YourApp'
function App() {
return (
)
}
export default App
```
## Anatomy
```tsx
import { Tooltip } from 'tamagui' // or '@tamagui/tooltip'
export default () => (
{/* ... */}
)
```
## API Reference
### Tooltip
Contains every component for the tooltip.
void',
required: false,
},
{
name: 'modal',
type: 'boolean',
default: 'true',
required: false,
description: `Renders into root of app instead of inline`,
},
{
name: 'stayInFrame',
type: 'ShiftProps',
required: false,
description: `See floating-ui shift()`,
},
{
name: 'allowFlip',
type: 'FlipProps',
required: false,
description: `See floating-ui flip`,
},
{
name: 'offset',
type: 'OffsetOptions',
required: false,
description: `Determines the distance the Popover appears from the target, see floating-ui offset().`,
},
]}
/>
If using `modal={true}` (which is `true` by default), refer to the [PortalProvider
installation](/ui/tooltip/1.0.0#portalprovider) for more information.
### Tooltip.Trigger
Used to trigger opening of the popover when uncontrolled, see YStack in [Stacks](/docs/components/stacks).
### Tooltip.Content
Renders as SizableStack (see [Stacks](/docs/components/stacks)) with an extra `size` prop that accepts any `SizeTokens`.
### Tooltip.Anchor
Renders as YStack, see [Stacks](/docs/components/stacks).
When you want the Trigger to be in another location from where the Tooltip attaches, use Anchor. When used, Anchor is where the Tooltip will attach, while Trigger will open it.
### TooltipGroup
This allows you to logically group any tooltips rendered below this component. You can control their delay props, and components inside a TooltipGroup will be smart about opening quicker if you are moving between targets with tooltips, ensuring that subsequent tooltips show immediately rather than after a delay.
See the [Floating UI docs](https://floating-ui.com/docs/floatingdelaygroup) for full details on how this works.
## components/tooltip/1.122.0
---
title: Tooltip
description: A tooltip on web, with only accessibility output on native.
name: tooltip
component: Tooltip
package: tooltip
demoName: Tooltip
---
```tsx hero template=Tooltip
```
Note that Tooltip doesn't render on native platforms.
## Installation
Tooltip is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/tooltip
```
### PortalProvider
If you are not using `tamagui` (but rather `@tamagui/core`) you'll need to install the `@tamagui/portal` package:
```bash
npm install @tamagui/portal
```
Then add `PortalProvider` to the root of your app:
```tsx fileName="App.tsx"
import { PortalProvider } from '@tamagui/portal'
import YourApp from './components/YourApp'
function App() {
return (
)
}
export default App
```
## Anatomy
```tsx
import { Tooltip } from 'tamagui' // or '@tamagui/tooltip'
export default () => (
{/* ... */}
)
```
## API Reference
### Tooltip
Contains every component for the tooltip.
void',
required: false,
},
{
name: 'modal',
type: 'boolean',
default: 'true',
required: false,
description: `Renders into root of app instead of inline`,
},
{
name: 'stayInFrame',
type: 'ShiftProps',
required: false,
description: `See floating-ui shift()`,
},
{
name: 'allowFlip',
type: 'FlipProps',
required: false,
description: `See floating-ui flip`,
},
{
name: 'offset',
type: 'OffsetOptions',
required: false,
description: `Determines the distance the Popover appears from the target, see floating-ui offset().`,
},
]}
/>
If using `modal={true}` (which is `true` by default), refer to the [PortalProvider
installation](#portalprovider) for more information.
### Tooltip.Trigger
Used to trigger opening of the popover when uncontrolled, see YStack in [Stacks](/docs/components/stacks).
### Tooltip.Content
Renders as SizableStack (see [Stacks](/docs/components/stacks)) with an extra `size` prop that accepts any `SizeTokens`.
### Tooltip.Anchor
Renders as YStack, see [Stacks](/docs/components/stacks).
When you want the Trigger to be in another location from where the Tooltip attaches, use Anchor. When used, Anchor is where the Tooltip will attach, while Trigger will open it.
### TooltipGroup
This allows you to logically group any tooltips rendered below this component. You can control their delay props, and components inside a TooltipGroup will be smart about opening quicker if you are moving between targets with tooltips, ensuring that subsequent tooltips show immediately rather than after a delay.
See the [Floating UI docs](https://floating-ui.com/docs/floatingdelaygroup) for full details on how this works.
### closeOpenTooltips
A small helper function of type `() => void` that will close any open tooltips.
## components/tooltip/2.0.0
---
title: Tooltip
description: A tooltip on web, with only accessibility output on native
name: tooltip
component: Tooltip
package: tooltip
demoName: Tooltip
---
```tsx hero template=Tooltip
```
Tooltip displays contextual information when hovering over an element. It waits for your mouse to stop moving before appearing, supports animations, and [automatically stacks](/ui/z-index) above other content.
Note that Tooltip doesn't render on native platforms.
## Installation
Tooltip is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/tooltip
```
## Anatomy
```tsx
import { Tooltip } from 'tamagui' // or '@tamagui/tooltip'
export default () => (
{/* ... */}
)
```
## API Reference
### Tooltip
Contains every component for the tooltip.
void',
required: false,
description: `Event handler called when the open state changes.`,
},
{
name: 'modal',
type: 'boolean',
default: 'true',
required: false,
description: `Renders into root of app instead of inline.`,
},
{
name: 'stayInFrame',
type: 'ShiftProps | boolean',
required: false,
default: '{ padding: 10 }',
description: `Shifts the tooltip horizontally to stay within viewport bounds. Pass an object to customize shift behavior (mainAxis, crossAxis, padding).`,
},
{
name: 'allowFlip',
type: 'FlipProps',
required: false,
description: `See floating-ui flip().`,
},
{
name: 'offset',
type: 'OffsetOptions',
required: false,
description: `Determines the distance the Popover appears from the target, see floating-ui offset().`,
},
{
name: 'zIndex',
type: 'number',
required: false,
description: `Sets the z-index of the tooltip portal. Only needed for global/scoped tooltips mounted at the root - inline tooltips automatically participate in z-index stacking. See the Scoping section below.`,
},
]}
/>
If using `modal={true}` (which is `true` by default), refer to the [PortalProvider
installation](#portalprovider) for more information.
### Tooltip.Trigger
Used to trigger opening of the popover when uncontrolled, see YStack in [Stacks](/docs/components/stacks).
### Tooltip.Content
Renders as SizableStack (see [Stacks](/docs/components/stacks)) with an extra `size` prop that accepts any `SizeTokens`.
### Tooltip.Anchor
Renders as YStack, see [Stacks](/docs/components/stacks).
When you want the Trigger to be in another location from where the Tooltip attaches, use Anchor. When used, Anchor is where the Tooltip will attach, while Trigger will open it.
### TooltipGroup
This allows you to logically group any tooltips rendered below this component. You can control their delay props, and components inside a TooltipGroup will be smart about opening quicker if you are moving between targets with tooltips, ensuring that subsequent tooltips show immediately rather than after a delay.
See the [Floating UI docs](https://floating-ui.com/docs/floatingdelaygroup) for full details on how this works.
### closeOpenTooltips
A small helper function of type `() => void` that will close any open tooltips.
## Scoping
Tooltip supports scoping which lets you mount a single Tooltip instance at
the root of your app, while having deeply nested Trigger components anywhere
in your tree attach to that single parent Tooltip.
This is useful for performance - you only render `Tooltip.Trigger` in your
list items or buttons, while the heavier `Tooltip` and `Tooltip.Content` live
at the root. It also lets you style all your tooltips consistently in one place.
When using a global scoped tooltip, you should set `zIndex` to ensure tooltips appear above dialogs and other portaled content. This is because the global tooltip's portal is mounted outside the stacking context of other portals. Inline tooltips (rendered alongside their trigger) automatically participate in z-index stacking and don't need this.
```tsx fileName=_layout.tsx
import { Tooltip } from 'tamagui'
export default ({ children }) => (
// zIndex needed for global tooltips to appear above dialogs
{/* your tooltip content renders here */}
{/* the rest of your app renders inside */}
{children}
)
```
```tsx fileName=MyButton.tsx
export default () => (
)
```
The `scope` prop on `Trigger` connects it to the `Tooltip` with the matching scope.
## components/unspaced/1.0.0
---
title: Unspaced
description: Avoids spacing for children inside a spacing container.
name: html
component: Unspaced
---
While the `space` property is deprecated, Unspaced lives on in a better form, one which is easily back-ported to add Unspaced support (as well as adding `gap` support).
When using the `space` style prop, you may want some children to not be spaced.
Use Unspaced:
```tsx
import { Text, Unspaced, View } from '@tamagui/core'
export default () => (
{/* space */}
{/* no */}
Some absolute positioned text
)
```
If you want the item to be visually hidden as well as unspaced, see
[VisuallyHidden](/docs/components/visually-hidden), which uses Unspaced but also hides the contents in an accessible manner.
## components/unspaced/2.0.0
---
title: Unspaced
description: Avoids spacing for children inside a spacing container
name: unspaced
component: Unspaced
package: core
---
While the `space` property is deprecated, Unspaced lives on in a better form, one which is easily back-ported to add Unspaced support (as well as adding `gap` support).
When using the `space` style prop, you may want some children to not be spaced. Use Unspaced:
## Usage
```tsx
import { Text, Unspaced, View } from '@tamagui/core'
export default () => (
{/* space */}
{/* no */}
Some absolute positioned text
)
```
If you want the item to be visually hidden as well as unspaced, see
[VisuallyHidden](/docs/components/visually-hidden), which uses Unspaced but also hides the contents in an accessible manner.
## components/visually-hidden/1.0.0
---
title: Visually Hidden
description: Hide content accessibly.
name: html
component: VisuallyHidden
---
VisuallyHidden hides an item but ensures it remains visible to accessibility readers.
## Installation
VisuallyHidden is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/visually-hidden
```
## Usage
Simply wrap the content you want hidden in VisuallyHidden:
```tsx
import { Text, VisuallyHidden } from 'tamagui'
export default () => (
Add annotations here
)
```
When using with the `space` property, it will avoid double-spacing:
```tsx
import { H1, Text, VisuallyHidden, YStack } from 'tamagui'
export default () => (
Title
Add annotations here
)
```
## components/visually-hidden/2.0.0
---
title: Visually Hidden
description: Hide content accessibly
name: visually-hidden
component: VisuallyHidden
package: visually-hidden
---
VisuallyHidden hides an item but ensures it remains visible to accessibility readers.
## Installation
VisuallyHidden is already installed in `tamagui`, or you can install it independently:
```bash
npm install @tamagui/visually-hidden
```
## Usage
Simply wrap the content you want hidden in VisuallyHidden:
```tsx
import { Text, VisuallyHidden } from 'tamagui'
export default () => (
Add annotations here
)
```
When using with the `space` property, it will avoid double-spacing:
```tsx
import { H1, Text, VisuallyHidden, YStack } from 'tamagui'
export default () => (
Title
Add annotations here
)
```
## components/z-index/2.0.0
---
title: Z-Index & Stacking
description: How Tamagui automatically stacks overlays and floating content
name: z-index
---
Tamagui includes an automatic stacking system that ensures overlays like dialogs, popovers, sheets, and tooltips layer correctly without manual z-index management.
## How It Works
When you open overlay components, Tamagui automatically assigns z-index values so that:
- **Later-opened content appears above earlier content** - Open two dialogs? The second one stacks above the first.
- **Nested content appears above its parent** - A tooltip inside a dialog automatically renders above the dialog.
- **Closing restores order** - When content closes, z-index values are reclaimed.
This means you typically don't need to think about z-index at all.
## When to Set zIndex
Only set `zIndex` when you need to override the automatic stacking. Common cases:
- **Fixed headers/footers** - If you have a sticky header at `z-index: 100`, overlays need to appear above it (they do by default).
- **Third-party libraries** - If integrating with libraries that use high z-index values.
- **Custom stacking requirements** - When you need specific layering that differs from open-order.
```tsx
// Only if you need to override automatic stacking
```
## Component Defaults
All overlay components use the automatic stacking system. Here's where to set `zIndex` if needed:
| Component | Where to set zIndex |
|-----------|---------------------|
| [Dialog](/ui/dialog) | `