# Tamagui > description: A vertically stacked set of interactive headings with content. --- # Source: https://tamagui.dev/ui/accordion.md --- 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). --- # Source: https://tamagui.dev/ui/alert-dialog.md --- 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... */} ) } ``` --- # Source: https://tamagui.dev/ui/anchor.md --- 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: --- # Source: https://tamagui.dev/docs/core/animations.md --- title: Animations description: Swap out animation drivers per-platform or at runtime --- ```tsx hero template=Animations ``` Add animations to Tamagui with an animation driver. See the configuration docs for more on [how to set it up, and how to set up different animation drivers per-platform](/docs/core/configuration#animations). Animation drivers are designed to be swappable, so you can use lightweight CSS animations or other web-focused animation libraries on the web, while using larger but more advanced libraries like `reanimated` on native - all without having to change a line outside of configuration. ## Installation ### CSS The `@tamagui/animations-css` package works with the tamagui compiler and runtime to give you simple ways to share typed animations across all your components. To install it add to your package.json: ```bash yarn add @tamagui/animations-css ``` Then add it to your [config](/docs/core/configuration): ```tsx import { createAnimations } from '@tamagui/animations-css' import { createTamagui } from 'tamagui' export default createTamagui({ animations: createAnimations({ fast: 'ease-in 150ms', medium: 'ease-in 300ms', slow: 'ease-in 450ms', }), // ... }) ``` At runtime, the plugin does very little except to set the `transition` property in CSS. At compile-time, the compiler does the same, ensuring you get all the benefits of prop removal and view flattening even when using animations. ### React Native Animated [React Native's Animated library](https://reactnative.dev/docs/animated) is the animation library that comes built into React Native and React Native Web. To install it add to your package.json: ```bash yarn add @tamagui/animations-react-native ``` Then add it to your [config](/docs/core/configuration): ```tsx import { createAnimations } from '@tamagui/animations-react-native' import { createTamagui } from 'tamagui' export default createTamagui({ animations: createAnimations({ fast: { damping: 20, mass: 1.2, stiffness: 250, }, medium: { damping: 10, mass: 0.9, stiffness: 100, }, slow: { damping: 20, stiffness: 60, }, }), // ... }) ``` ### Reanimated [Reanimated](https://docs.swmansion.com/react-native-reanimated/) is an animation library that targets React Native and React Native Web. It runs off-thread animations, and provides simple syntax and hooks. To install it add to your package.json: ```bash yarn add @tamagui/animations-moti react-native-reanimated ``` Tamagui leverages and appreciates the popular open source library [Moti](https://moti.fyi) for the Reanimated driver as it saved us many lines of complex code. Add your animations to your [configuration](/docs/core/configuration): ```tsx import { createAnimations } from '@tamagui/animations-moti' import { createTamagui } from 'tamagui' export default createTamagui({ animations: createAnimations({ fast: { type: 'spring', damping: 20, mass: 1.2, stiffness: 250, }, medium: { type: 'spring', damping: 10, mass: 0.9, stiffness: 100, }, slow: { type: 'spring', damping: 20, stiffness: 60, }, }), // ... }) ``` At runtime, this plugin parses animatable style properties and hands them over to reanimated off-thread, using worklets. It doesn't do anything at compile time - reanimated must run via JS. --- Note the keys match between CSS and reanimated, so you can swap them out. The Animated driver in React Native Web can be excluded from your bundle with either the Webpack or Next.js plugins with [`excludeReactNativeWebExports` compiler option](#excludeReactNativeWebExports). ### Usage The `animation` can now accept `slow` as a value. By default, animations will apply to all animatable styles, a lot like setting `all` in a CSS `transition`. Let's test this by setting `hoverStyle`: Here's an example animating `hoverStyle`: ```tsx hero template=AnimationsHover ``` ### The animation props rules If you add an `animation` prop, you must always keep the prop. If you need the animation to be disabled, pass false, null or even undefined if it suits you. The spring-based animation drivers have expensive hooks that would degrate runtime performance if present on every component. As a workaround, the animation hooks are called conditionally on whether the animation key is present in the props object. So, `` rather than ``. If you'd like to remove or add an animation prop after a component has already rendered, you'd have to change the key. ### enterStyle Setting `enterStyle` styles on any component tell it to start with those styles, and after mount animate to their flat styles: ```tsx hero template=AnimationsEnter ``` ### Granular animations The `animation` prop accepts a string or a more complex object to customize animations per-property. The basic object we'll call an `AnimationConfig`, looks like this: ```tsx import { YStack } from 'tamagui' export default () => ( ) ``` Note that values can either map to `AnimationKey` as a string, or to `{ type: AnimationKey, ...configuration }` You can set a default value using a two-arity array with the default in the first position: ```tsx import { YStack } from 'tamagui' export default () => ( ) ``` ### animateOnly The `animateOnly` prop will limit your animation config to certain keys. It accepts an array of strings that correspond to style property names. ## AnimatePresence ### exitStyle AnimatePresence animates direct children before they unmount. It's inspired by and forked from [Framer Motion](https://github.com/framer/motion), but works with any animation in Tamagui. To use with `@tamagui/core`, install and import `@tamagui/animate-presence`. It's already bundled and exported from `tamagui`. You can use it simply with `enterStyle` + `exitStyle`: ```tsx import { AnimatePresence, View } from 'tamagui' export const MyComponent = ({ isVisible }) => ( {isVisible && ( )} ) ``` Note you don't even need to set `opacity` on the base style. Tamagui knows to normalize styles like opacity and scale to 1 (and y to 0) if it's not defined on the base styles but is defined on `enterStyle` or `exitStyle`. Wrap one or more tamagui components with AnimatePresence. This component will animate on enter and exit. Animated child components must each have a unique key prop so AnimatePresence can track their presence in the tree. ### The `custom` prop ```tsx hero template=AnimationsPresence ``` AnimatePresence also takes a `custom` property that allows you to update a variant of the animated child before it runs it's exit animation. This is useful for animating a child out of the screen before it unmounts in a different direction, like the example above: ```tsx import { AnimatePresence } from '@tamagui/animate-presence' import { ArrowLeft, ArrowRight } from '@tamagui/lucide-icons' import { useState } from 'react' import { Button, Image, XStack, YStack, styled } from 'tamagui' const GalleryItem = styled(YStack, { zIndex: 1, x: 0, opacity: 1, fullscreen: true, variants: { // 1 = right, 0 = nowhere, -1 = left going: { ':number': (going) => ({ enterStyle: { x: going > 0 ? 1000 : -1000, opacity: 0, }, exitStyle: { zIndex: 0, x: going < 0 ? 1000 : -1000, opacity: 0, }, }), }, } as const, }) const photos = [ 'https://picsum.photos/500/300', 'https://picsum.photos/501/300', 'https://picsum.photos/502/300', ] const wrap = (min: number, max: number, v: number) => { const rangeSize = max - min return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min } export function Demo() { const [[page, going], setPage] = useState([0, 0]) const imageIndex = wrap(0, photos.length, page) const paginate = (going: number) => { setPage([page + going, going]) } return ( ``` ### 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: --- # Source: https://tamagui.dev/ui/card.md --- title: Card description: Sizable, themeable cards with a flexible API. name: card component: Card package: card demoName: Card --- ```tsx hero template=Card ``` ## Installation Card is already installed in `tamagui`, or you can install it independently: ```bash npm install @tamagui/card ``` ## Anatomy ```tsx import { Card } from 'tamagui' // or '@tamagui/card' export default () => ( {/* any other components */} ) ``` ## API Reference ### Card Frame of the card, extends [ThemeableStack props](/docs/components/stacks#themeablestack), adding: ### Card.Header Extends [ThemeableStack](/docs/components/stacks#themeablestack), adding: ### Card.Footer Extends [ThemeableStack](/docs/components/stacks#themeablestack), adding: ### Card.Background Extends [YStack](/docs/components/stacks), set to `fullscreen` and zIndex below Header/Footer. --- # Source: https://tamagui.dev/ui/checkbox.md --- title: Checkbox description: Toggle state in forms. name: checkbox component: Checkbox package: checkbox demoName: Checkbox --- Styled Unstyled Headless ```tsx hero template=Checkbox ```` ```tsx hero template=CheckboxUnstyled ```` ```tsx hero template=CheckboxHeadless ```` ## Installation Checkbox is already installed in `tamagui`, or you can install it independently: ```bash npm install @tamagui/checkbox ```` Checkbox is already installed in `tamagui`, or you can install it independently: ```bash npm install @tamagui/checkbox ``` To use the headless checkbox, you want to import it from the `@tamagui/checkbox-headless` package. This package has no dependency on `@tamagui/core`, but still works off the react-native APIs. This means you can bring your own style library. ```bash npm install @tamagui/checkbox-headless ``` ## Usage ```tsx import { Check } from '@tamagui/lucide-icons' import { Checkbox } from 'tamagui' export default () => ( ) ``` Use the `createCheckbox` export to create a fully custom checkbox that still uses the Tamagui styling system. This is similar to setting `unstyled`, but goes a bit further. It doesn't add any types for `size` or `unstyled`, and it won't automatically apply the `active` theme. It does pass the `checked` prop down as indicated in the types of `createCheckbox`. ```tsx template=CheckboxUnstyled ``` Using the `useCheckbox` API, you can make your own Checkbox from scratch. ```tsx template=CheckboxHeadless ``` ## API Reference ### Checkbox `Checkbox` extend ThemeableStack inheriting all the [props](/docs/components/stacks#themeablestack), plus: void', description: 'Callback that fires when the checkbox state is changed.', }, { name: 'sizeAdjust', type: 'number', description: `Adjust the checkbox size scaling by this number.`, }, { name: 'scaleIcon', type: 'number', description: `Scale the indicator icon more than usual by this number.`, }, { name: 'scaleSize', type: 'number', default: '0.5', description: `The Tamagui size tokens should map to the height of a button at any given step. This means you want somewhat smaller checkboxes typically.`, }, { name: 'unstyled', required: false, type: `boolean`, description: `Removes all default Tamagui styles.`, }, ]} /> ### Checkbox.Indicator `Checkbox.Indicator` extend ThemeableStack inheriting all the [props](/docs/components/stacks#themeablestack), plus: --- # Source: https://tamagui.dev/docs/intro/compiler-install.md --- title: Tamagui Compiler description: Adding the compiler to your apps --- The Tamagui Compiler significantly improves performance of both web and native applications through partial analysis and view flattening. See the [Benchmarks](/docs/intro/benchmarks) or a more [in-depth background](/docs/intro/why-a-compiler). Note that Tamagui features work at compile-time and runtime, so installing the compiler is optional, and in fact we recommend only setting it up once you're ready for production. The compiler uses Babel to analyze JSX and `styled` functions, then attempts statically analyze them and optimize them down to platform-native primitives. The end result is less abstraction - like a `div` on web, or plain React Native `View` on native:

The compiler generates built versions of your components and config into a `.tamagui` directory. You'll want to add that directory to your `.gitignore`. ## Install There are plugins for a variety of bundlers, or you can use the `@tamagui/cli` to compile in-place: ### Webpack ```bash yarn add tamagui-loader ``` We have a full example of a plain Webpack or Vite setup in the simple starter accessible through `npm create tamagui@latest`, which shows a complete configuration with more detail. Add `tamagui-loader` and set up your `webpack.config.js`. You can set it up more manually like so: ```js const { shouldExclude } = require('tamagui-loader') const tamaguiOptions = { config: './tamagui.config.ts', components: ['tamagui'], importsWhitelist: ['constants.js', 'colors.js'], logTimings: true, disableExtraction: process.env.NODE_ENV === 'development', // optional advanced optimization of styled() definitions within your app itself, not just ones in your components option // default is false enableDynamicEvaluation: false, } module.exports = { resolve: { alias: { // Resolve react-native to react-native-web 'react-native$': require.resolve('react-native-web'), // optional, for lighter svg icons on web 'react-native-svg': require.resolve('@tamagui/react-native-svg'), }, }, module: { rules: [ { test: /\.[jt]sx?$/, // you'll likely want to adjust this helper function, // but it serves as a decent start that you can copy/paste from exclude: (path) => shouldExclude(path, __dirname, tamaguiOptions), use: [ // optionally thread-loader for significantly faster compile! 'thread-loader', // works nicely alongside esbuild { loader: 'esbuild-loader', }, { loader: 'tamagui-loader', options: tamaguiOptions, }, ], }, ], }, } ``` Or you can use the TamaguiPlugin which automates some of this setup for you: ```tsx const { TamaguiPlugin } = require('tamagui-loader') module.exports = { plugins: [ new TamaguiPlugin({ config: './tamagui.config.ts', components: ['tamagui'], importsWhitelist: ['constants.js', 'colors.js'], logTimings: true, disableExtraction: process.env.NODE_ENV === 'development', }), ], } ``` Some notes on the options: - _importsWhitelist_: Tamagui takes a conservative approach to partial evaluation, this field whitelists (matching against both .ts and .js) files to allow files that import them to read and use their values during compilation. Typically colors and constants files. - _disableExtraction_: Useful for faster developer iteration as your design system hot reloads more reliably. ### Vite See the [Vite guide](/docs/guides/vite) for more complete setup. Add `@tamagui/vite-plugin` and update your `vite.config.ts`: ```tsx import { tamaguiPlugin } from '@tamagui/vite-plugin' export default defineConfig({ plugins: [ tamaguiPlugin({ // points to your tamagui config file config: 'src/tamagui.config.ts', // points to any linked packages or node_modules // that have tamagui components to optimize components: ['tamagui'], // turns on the optimizing compiler optimize: true, }), ], }) ``` ### Next.js See the ([guide](/docs/guides/next-js)) for more complete setup. Add `@tamagui/next-plugin` and configure your `next.config.js`. Here we show a fuller scope of the options ```js // note next-compose-plugins somewhat unmaintained // you can use a simple two-liner instead, see: // https://github.com/cyrilwanner/next-compose-plugins/issues/59#issuecomment-1192523231 const withPlugins = require('next-compose-plugins') const { withTamagui } = require('@tamagui/next-plugin') export default withPlugins([ withTamagui({ config: './tamagui.config.ts', components: ['tamagui'], // rest are all optional: // disable static extraction, faster to iterate in dev mode (default false) disableExtraction: process.env.NODE_ENV === 'development', // Exclude react-native-web modules to lighten bundle excludeReactNativeWebExports: ['Switch', 'ProgressBar', 'Picker'], // By default, we configure webpack to pass anything inside your root or design system // to the Tamagui loader. If you are importing files from an external package, use this: shouldExtract: (path: string, projectRoot: string) => { if (path.includes('../packages/myapp')) { return true } }, // Advanced: // Many packages give difficulty to the nextjs server-side (node) runtime when un-bundled. // for example, tamagui configures aliases like react-native => react-native-web. // if you're running into a module that has errors importing react-native, you'll want to // use a custom shouldExcludeFromServer function to include it (or override the default). // this is the exact same return type as webpack.externals. // returning undefined will let tamagui handle it, boolean or other values to override. shouldExcludeFromServer: ({ fullPath, request }) => { if (fullPath.includes('my-module')) { return 'commonjs ' + commonjs } if (request === 'some-hard-to-bundle-package') { return true } }, }), ]) ``` Note: If running into issues, the environment variable `IGNORE_TS_CONFIG_PATHS` to "true" can fix issues with Tamagui being resolved incorrectly. See the [Next.js Guide](/docs/guides/next-js) for more details on setting up your app. ### Babel / Metro Note that the `@tamagui/babel-plugin` is completely optional, and on native Tamagui doesn't optimize as much as on web, so leaving it out is actually recommended to start. If later on you feel the need for a bit more speed, you can try adding it. ```bash yarn add @tamagui/babel-plugin ``` Add to your `babel.config.js`: ```js module.exports = { plugins: [ [ '@tamagui/babel-plugin', { components: ['tamagui'], config: './tamagui.config.ts', importsWhitelist: ['constants.js', 'colors.js'], logTimings: true, disableExtraction: process.env.NODE_ENV === 'development', }, ], ], } ``` Currently the native compiler doesn't optimize as much as it could. It bails out if it encounters any theme usage, like ``. If you are on version `1.75` or greater, you can test enabling this experimental optimization by adding a new property with the key `experimentalFlattenThemesOnNative` set to true in the above config object and that will make the compiler to flat and extract any theme usage or dynamic values. ### Expo [Check out the Expo guide](/docs/guides/expo) for more information on setting up Expo. It's as simple as adding the babel plugin. ### CLI-Based In-Place Compilation For bundlers that don't have a Tamagui plugin yet (like Turbopack), or if you prefer a simple setup, you can use `@tamagui/cli` to pre-compile your components in-place before your build step. This approach is meant for **production builds only** and should run in your deployment pipeline, not during development. It rewrites files in place which will mess up your working directory, but makes it highly compatible with any bundler or tool. The downside is you don't get the helpful development compatibility parts of the plugins, plus dev-mode debugging and `data-` attributes. #### Setup 1. Install: ```bash yarn add -D @tamagui/cli ``` 2. Create a `tamagui.build.ts` config file in your project root: ```ts import type { TamaguiBuildOptions } from 'tamagui' export default { config: './tamagui.config.ts', components: ['tamagui'], importsWhitelist: ['constants.js', 'colors.js'], outputCSS: './public/tamagui.css', } satisfies TamaguiBuildOptions ``` 3. Add a build script to your `package.json`: ```json { "scripts": { "build": "tamagui build ./src && next build" } } ``` #### Usage ```bash # Build all components in a directory (web + native by default) npx tamagui build ./src # Build for web only npx tamagui build --target web ./src # Build for native only npx tamagui build --target native ./src # Build a specific file npx tamagui build ./src/components/MyComponent.tsx # Include/exclude patterns npx tamagui build --include "components/**" --exclude "**/*.test.tsx" ./src # Verify minimum optimizations (useful in CI) npx tamagui build --target web --expect-optimizations 10 ./src ``` #### CI Verification with --expect-optimizations The `--expect-optimizations` flag ensures your build is actually optimizing components. This is useful in CI to catch configuration issues: ```json { "scripts": { "build": "tamagui build --target web --expect-optimizations 10 ./src && next build" } } ``` If the compiler produces fewer than the expected number of optimizations, the build will fail with an error message showing the actual count. This helps catch: - Misconfigured `components` array - Wrong source paths - Configuration files not being found #### Platform-Specific File Handling The CLI automatically handles platform-specific files (`.web.tsx`, `.native.tsx`, `.ios.tsx`, `.android.tsx`): - Files with `.web.tsx` or `.ios.tsx` extensions are optimized for web only - Files with `.native.tsx` or `.android.tsx` extensions are optimized for native only - Base files (`.tsx`) without platform-specific versions are optimized for all platforms - If both `.web.tsx` and `.native.tsx` exist, the base `.tsx` file is skipped #### Package.json Exports Support The CLI supports `package.json` exports for path-specific imports. For example: ```json { "exports": { ".": "./src/index.tsx", "./components/Button": "./src/Button.tsx" } } ``` Both import styles work: ```tsx import { Button } from '@my/ui' import { Button } from '@my/ui/components/Button' ``` #### Integration Examples This works with **any build tool** - just run `tamagui build` before your build command. Here are some examples: **Next.js with Turbopack** (Turbopack doesn't support plugins yet): ```json { "scripts": { "dev": "next dev --turbopack", "build": "tamagui build --target web ./src && next build" } } ``` **Vite, Remix, or any other bundler:** ```json { "scripts": { "build": "tamagui build --target web ./src && vite build" } } ``` **React Native / Expo:** ```json { "scripts": { "build:ios": "tamagui build --target native ./src && eas build --platform ios", "build:android": "tamagui build --target native ./src && eas build --platform android" } } ``` The Tamagui CLI optimizes your components in-place, then your bundler processes the already-optimized files. ## Props All compiler plugins accept the same options: ### Dynamic Evaluation By default the Tamagui compiler only optimizes `styled` expressions found in the modules defined by your `components` config. This means if you do an inline `styled()` inside your actual app directory, it will default to runtime style insertion. This is typically Good Enough™️. As long as you define most of your common components there, you'll get a very high hit rate of compiled styles being used and runtime generation being skipped, as atomic styles with your design system tokens will be mostly pre-generated. Tamagui has _experimental_ support for loading any component, even if it occurs somewhere outside your configured components modules. This is called "dynamic loading", for now. You can enable it with the setting `enableDynamicEvaluation` as seen above in the props table. The way it works is, when the compiler detects a styled() expression outside one of the defined component directories, it will run the following: 1. First, read the file and use a custom `babel` transform to _force_ all top-level variables to be exported. 2. Then, run `esbuild` and bundle the entire file to a temporary file in the same directory, something like `.tamagui-dynamic-eval-ComponentName.js` 3. Now, read the file in and load all new definitions found. 4. Finally, continue with optimization, using the newly optimized component. You may see why this is experimental. It's very convenient as a developer, but has a variety of edge cases that can be confusing or breaking, and we want to avoid installation woes. Though it does continue on error and work generally, it outputs warnings in Webpack currently due to our plugin not properly indicating to Webpack about the new files (a fixable bug), which causes big yellow warning output and a cache de-opt. We're leaving this feature under the environment variable while it matures. Let us know if you find it useful. ### Disabling the compiler You can disable the compiler optimizations for an entire file with a comment at the top of your file: ```tsx // tamagui-ignore ``` You can disable the compiler optimization for a single component with the boolean property `disableOptimization`: ```tsx import { View } from '@tamagui/core' export default () => ``` ### Web-only apps If you want autocompleted imports of `react-native` without having to install all the weight of react-native, you can set `react-native` version to `0.0.0`, and add `@types/react-native` at the latest version. --- # Source: https://tamagui.dev/docs/core/config-v4.md --- title: Quick Config description: Easy config and themes with @tamagui/config/v4 --- Config v4 simplifies configuration, generates much more useful themes, and adds a new helper function for generating your own theme suite called `createThemes`. First you'll want to add it: ```bash npm install @tamagui/config ``` Using the new `defaultConfig` is the easiest way to start: ```tsx fileName="tamagui.config.ts" import { defaultConfig } from '@tamagui/config/v4' import { createTamagui } from 'tamagui' export const config = createTamagui(defaultConfig) type CustomConfig = typeof config // ensure types work declare module 'tamagui' { interface TamaguiCustomConfig extends CustomConfig {} } ``` It gives you a robust suite of themes, a few shorthands that mostly align with Tailwind, and default settings that prevent bugs. If you like it but want to make some changes, you can [copy and paste the source code](https://github.com/tamagui/tamagui/blob/5b0c075e92688ac85737fe97c98cd77322f034b0/code/core/config/src/v4.ts) into your app and customize to your taste. If you want to learn to create your own custom theme suite rather than use the included defaults, check out the [Creating Custom Themes Guide](/docs/guides/theme-builder). We recommend adding `settings.styleCompat` to the default config, setting it to be "react-native". This will align the default flexBasis of `flex` to be `0`, not `auto`, matching the default in React Native. This setting will become the default in the upcoming Tamagui v2 release. We left it out of Config v4 because we wanted an easier transition for existing users, but if you are a new user, we recommend this setting. --- ### Default Configuration You can take or leave as much of the default configuration as you please. Each part is exported separately, or all together as `defaultConfig`. #### Themes Config v4 has a new helper function `createThemes`, an opinionated way to generate a suite of themes. It also comes with default themes that include minimal grayscale light and dark themes, and an inverted "accent" theme. It's easiest to get a feel for both createThemes the default themes by reading the source for how `defaultThemes` are defined: ```tsx fileName=themes.ts import * as Colors from '@tamagui/colors' import { createThemes, defaultComponentThemes } from '@tamagui/config/v4' const darkPalette = [ '#050505', '#151515', '#191919', '#232323', '#282828', '#323232', '#424242', '#494949', '#545454', '#626262', '#a5a5a5', '#fff', ] const lightPalette = [ '#fff', '#f8f8f8', 'hsl(0, 0%, 96.3%)', 'hsl(0, 0%, 94.1%)', 'hsl(0, 0%, 92.0%)', 'hsl(0, 0%, 90.0%)', 'hsl(0, 0%, 88.5%)', 'hsl(0, 0%, 81.0%)', 'hsl(0, 0%, 56.1%)', 'hsl(0, 0%, 50.3%)', 'hsl(0, 0%, 42.5%)', 'hsl(0, 0%, 9.0%)', ] const lightShadows = { shadow1: 'rgba(0,0,0,0.04)', shadow2: 'rgba(0,0,0,0.08)', shadow3: 'rgba(0,0,0,0.16)', shadow4: 'rgba(0,0,0,0.24)', shadow5: 'rgba(0,0,0,0.32)', shadow6: 'rgba(0,0,0,0.4)', } const darkShadows = { shadow1: 'rgba(0,0,0,0.2)', shadow2: 'rgba(0,0,0,0.3)', shadow3: 'rgba(0,0,0,0.4)', shadow4: 'rgba(0,0,0,0.5)', shadow5: 'rgba(0,0,0,0.6)', shadow6: 'rgba(0,0,0,0.7)', } const extraColors = { black1: darkPalette[0], black2: darkPalette[1], black3: darkPalette[2], black4: darkPalette[3], black5: darkPalette[4], black6: darkPalette[5], black7: darkPalette[6], black8: darkPalette[7], black9: darkPalette[8], black10: darkPalette[9], black11: darkPalette[10], black12: darkPalette[11], white1: lightPalette[0], white2: lightPalette[1], white3: lightPalette[2], white4: lightPalette[3], white5: lightPalette[4], white6: lightPalette[5], white7: lightPalette[6], white8: lightPalette[7], white9: lightPalette[8], white10: lightPalette[9], white11: lightPalette[10], white12: lightPalette[11], } const generatedThemes = createThemes({ componentThemes: defaultComponentThemes, base: { palette: { dark: darkPalette, light: lightPalette, }, // for values we don't want being inherited onto sub-themes extra: { light: { ...Colors.blue, ...Colors.green, ...Colors.red, ...Colors.yellow, ...lightShadows, ...extraColors, shadowColor: lightShadows.shadow1, }, dark: { ...Colors.blueDark, ...Colors.greenDark, ...Colors.redDark, ...Colors.yellowDark, ...darkShadows, ...extraColors, shadowColor: darkShadows.shadow1, }, }, }, // inverse accent theme accent: { palette: { dark: lightPalette, light: darkPalette, }, }, childrenThemes: { blue: { palette: { dark: Object.values(Colors.blueDark), light: Object.values(Colors.blue), }, }, red: { palette: { dark: Object.values(Colors.redDark), light: Object.values(Colors.red), }, }, yellow: { palette: { dark: Object.values(Colors.yellowDark), light: Object.values(Colors.yellow), }, }, green: { palette: { dark: Object.values(Colors.greenDark), light: Object.values(Colors.green), }, }, }, }) export type TamaguiThemes = typeof generatedThemes /** * This is an optional production optimization: themes JS can get to 20Kb or more. * Tamagui has ~1Kb of logic to hydrate themes from CSS, so you can remove the JS. * So long as you server render your Tamagui CSS, this will save you bundle size: */ export const themes: TamaguiThemes = // we define this in our bundler plugins, but you can also use your framework/bundlers // built in environment variables to ensure this is shaken away on client js bundles process.env.TAMAGUI_ENVIRONMENT === 'client' && process.env.NODE_ENV === 'production' ? {} : (generatedThemes as any) ``` So what have we done? - `base` will always generate `light` and `dark` as your root themes. We plan to add support for generating just one base theme, but you can manually remove either light or dark if you please. - Our `base` themes are grayscale, defined by their palettes. - The `accent` option is an opinionated way to have a "contrasting theme". When set, it generates a few things: - `light_accent` and `dark_accent` themes - `$accent1` through `$accent12` on the base themes - `childrenThemes` allows us to set up some sub-themes easily, this is especially useful for when you want to make an area look like an error, success, or warning state. That's why we default to setting `green`, `yellow`, and `red`. Of course, you can swap these out for whatever you like. - We also are setting `componentThemes` to `defaultComponentThemes`, which will generate for us default styling for the Tamagui UI components. If you prefer to not have default component themes, you can leave this out. - You can use the `getTheme` callback to customize any generated theme. See the [theme-builder guide](/docs/guides/theme-builder#customizing-themes-with-gettheme) for details. #### Settings #### Media The new media queries in v4 are also more simplified and aligned to Tailwind: On the server, only xs and 2xs default to `true` to align generally give you a [mobile-first design](https://en.wikipedia.org/wiki/Responsive_web_design) setup, but of course you can change that. This only really affects `useMedia()`, as Tamagui generates proper SSR-safe CSS for media queries on the server for any style properties. #### Shorthands Config v4 has fewer shorthands, and aligns shorthands to Tailwind for familiarity: #### Tokens Tokens default tokens are defined as: ```tsx export const size = { $0: 0, '$0.25': 2, '$0.5': 4, '$0.75': 8, $1: 20, '$1.5': 24, $2: 28, '$2.5': 32, $3: 36, '$3.5': 40, $4: 44, $true: 44, '$4.5': 48, $5: 52, $6: 64, $7: 74, $8: 84, $9: 94, $10: 104, $11: 124, $12: 144, $13: 164, $14: 184, $15: 204, $16: 224, $17: 224, $18: 244, $19: 264, $20: 284, } export const space = { // ... space is the same as size, but also defines "negative" values for every size, like: '$-1': -20, } export const zIndex = { 0: 0, 1: 100, 2: 200, 3: 300, 4: 400, 5: 500, } export const radius = { 0: 0, 1: 3, 2: 5, 3: 7, 4: 9, true: 9, 5: 10, 6: 16, 7: 19, 8: 22, 9: 26, 10: 34, 11: 42, 12: 50, } ``` Note that `color` tokens aren't defined, instead we are just using themes. Also note that the "true" value on tokens is the "default" - Tamagui UI for now uses defaults to determine how to size various things out of the box. This isn't mandatory, and in version 2 of Tamagui we are working on a more clear solution. #### Fonts Only a `body` and `heading` font are exported, which both use "system" font families: You can create your own system font using the exported `createSystemFont` helper, or of course swap out your own fonts altogether. --- # Source: https://tamagui.dev/ui/dialog.md --- title: Dialog description: Show a modal with configurable layout and accessible actions. name: dialog component: Dialog package: dialog demoName: Dialog --- ```tsx hero template=Dialog ``` Dialog is a great way to show content inside a new floating window above content. Be sure to open the code example above for a copy-paste implementation. ## Installation Dialog is already installed in `tamagui`, or you can install it independently: ```bash npm install @tamagui/dialog ``` If you aren't using `tamagui` and instead using the `@tamagui/dialog` package separately, 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 { Dialog } from 'tamagui' // or '@tamagui/dialog' export default () => ( {/* ... */} {/* Optional: Control focus behavior */} {/* Focus scope will be applied to children */} ) ``` ## Scoping Dialog supports scoping which lets you mount one or more Dialog instances at the root of your app, while having a deeply nested child Trigger or Content attach to the proper parent Dialog instance. In performance sensitive areas you may want to take advantage of this, it allows you to only need to render the Dialog.Trigger inside the sensitive area as Dialogs aren't the cheapest component - they have a lot of functionality. Here's the basic anatomy of using `scope` and placing your Dialog higher up for performance: ```tsx fileName=_layout.tsx import { Dialog } from 'tamagui' // in your root layout: export default ({ children }) => ( {/* ... */} {/* the rest of your app, note that it's inside of Dialog */} {children} ) ``` ```tsx fileName=UserProfile.tsx export default () => ( ) ``` Note that the `Trigger` scope ties to the `Dialog` scope. ## Dismissal Behavior By default, dialogs can be dismissed by: - Clicking outside the dialog content (on the overlay) - Pressing the Escape key - Clicking a Dialog.Close element ### Modal vs Non-Modal Dialogs - **Modal dialogs** (`modal={true}`, which is the default): - In v1, have `disableOutsidePointerEvents` set to `true` by default - Still dismiss on outside click, but prevent interaction with elements behind the dialog - Prevent right-click dismissal (right-clicks on the overlay are ignored) - **Non-modal dialogs** (`modal={false}`): - Allow interaction with elements behind the dialog - Dismiss on any outside click - Do not trap focus ### Preventing Outside Dismissal To prevent a dialog from closing when clicking outside: ```tsx { event.preventDefault() }} > {/* Dialog contents */} ``` ## API Reference ### Dialog Contains every component for the dialog. Beyond [Tamagui Props](/docs/intro/props), adds: void', }, { name: 'modal', type: 'boolean', default: 'true', description: `Renders into root of app instead of inline`, }, { name: 'disableRemoveScroll', type: 'boolean', required: false, description: `Used to disable the automatic removal of scrolling from the page when open.`, }, ]} /> ### Dialog.Trigger Just [Tamagui Props](/docs/intro/props). ### Dialog.Portal Renders Dialog into appropriate container. Beyond [Tamagui Props](/docs/intro/props), adds: ### Dialog.Content Main container for Dialog content, this is where you should apply animations. Beyond [Tamagui Props](/docs/intro/props), adds: ### Dialog.Overlay Displays behind Content. Beyond [Tamagui Props](/docs/intro/props), adds: ### Dialog.Title Required. Can wrap in VisuallyHidden to hide. Defaults to H2, see [Headings](/docs/components/headings). ### Dialog.Description Required. Can wrap in VisuallyHidden to hide. Defaults to Paragraph, see [Paragraph](/docs/components/text). ### Dialog.Close Closes the Dialog, accepts the same props as YStack. Recommended to use with your own component and `asChild`. Just [Tamagui Props](/docs/intro/props). ### Dialog.FocusScope Provides access to the underlying FocusScope component used by Dialog 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`, }, ]} /> ### Dialog.Sheet When used with `Adapt`, Dialog will render as a sheet when that breakpoint is active. See [Sheet](/docs/components/sheet) for more props. Must use `Adapt.Contents` inside the `Dialog.Sheet.Frame` to insert the contents given to `Dialog.Content` ```tsx import { Dialog } from 'tamagui' // or '@tamagui/dialog' export default () => ( {/* ... */} {/* optionally change to sheet when small screen */} ) ``` Note that Dialog.Sheet currently doesn't preserve state of the contents when it transitions between Sheet and Portal. In the future, we can do this on the web using react-reparenting. ### 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... */} ) } ``` --- # Source: https://tamagui.dev/docs/core/exports.md --- title: 'Other exports' description: Helpful functions and constants --- Let's take a quick look through some of the useful other exports in `@tamagui/core`. ## Constants [Constants are re-exported from @tamagui/constants](https://github.com/tamagui/tamagui/blob/main/code/core/constants/src/constants.ts): - `isWeb` - True if targeting the web. Will be true both for SSR and client. - `isWindowDefined` - `typeof window !== 'undefined'` - `isServer` - `isWeb && !isWindowDefined`. - `isClient` - `isWeb && isWindowDefined`. - `useIsomorphicLayoutEffect` - `isServer ? useEffect : useLayoutEffect`. Helper for SSR rendering without warnings. - `isChrome` - client-side Chrome - `isWebTouchable` - web-only touch-device (client side only) - `isTouchable` - True for any touch device (client side only). --- ## Helpers ### getConfig The exported `getConfig` will return your fully parsed Tamagui config. This is safer than importing it directly as it avoids circular imports. In general you want to use `useTheme` to access themes, and `getTokens`/`getToken`/`getTokenValue` for tokens, but for other parts of the config this can be useful. ### insertFont ```tsx type insertFont = (name: string, fontIn: GenericFont) => ParsedFont ``` Will add a new font after initial createTamagui call. Where `GenericFont` is the same as a font passed to createTamagui, and `ParsedFont` is the font with the subkeys prefixed with `$` and turned into variable objects. ### updateFont The same as insertFont, but will update an existing font. ### isTamaguiComponent ```tsx type isTamaguiComponent (component: any; name?: string) => boolean ``` If no name given, true if a Tamagui component, if name given ensures it's the specific named Tamagui component. ### isTamaguiElement ```tsx type isTamaguiElement (child: any; name?: string) => boolean ``` If no name given, true if a Tamagui ReactElement, if name given ensures it's the specific named Tamagui component element. ### getTokens ```tsx ;() => TokensParsed ``` Returns the parsed Tamagui config object of all your tokens, can be used at runtime to get values from tokens. If you are looking to get a single token value, prefer `getToken` or `getTokenValue`. ### getToken ```tsx ;(name: Token, group?: keyof Tokens) => any ``` Given the specific name of a token or a name + group, will return the value as either a variable on the web, or raw value on native. So if you define a size token with key `small` and value of `14`: ```tsx getToken('$size.small') // returns on web var(--size-small), native 14 getToken('$small', 'size') // returns on web var(--size-small), native 14 ``` ### getTokenValue ```tsx ;(name: Token, group?: keyof Tokens) => any ``` Similar to getToken, but always returns the raw value rather than the variable name. If you define a size token with key `small` and value of `14`: ```tsx getTokenValue('$size.small') // returns 14 getTokenValue('$small', 'size') // returns 14 ``` ### getExpandedShorthands ```tsx ;(props: Object) => Object ``` Take props, returns new object with all shorthand props expanded. ### themeable ```tsx themeable(component: Comp): Comp ``` A higher order component that accepts `theme` and `themeInverse`, rendering them onto `Theme` before rendering your component. ### getVariable ```tsx type getVariable = (value: Variable) => string ``` If given a `Variable` - which comes from a parsed theme or token returned from `createTamagui`, `useTheme` or `getTokens` (read more [on the useTheme docs](/docs/core/use-theme)). Calling `getVariable(useTheme().color)` returns `var(--color)` on the web, and `#fff` on other platforms. ### setOnLayoutStrategy This is a low-level utility to control `onLayout` performance. By default, Tamagui `onLayout` on the web uses the `"async"` strategy (see below), which gives a good balance of accuracy and performance. For extremely accurate to native `onLayout`, you can use `"sync"`, but it can cause performance issues in typical usage. Call `setOnLayoutStrategy` with a single string argument: - `"off"` will pause all `onLayout` callbacks from running. - `"sync"` will run every frame and update every frame if necessary. - `"async"` will use an async getBoundingClientRect strategy that avoids repaints/reflows, and also waits 2 frames of debouncing before triggering the callback. The `async` stretegy generally has great performance on web, and it will also ensure to call `onLayout` sync on mount the first time, so you avoid jitters. --- ## Hooks ### useProps Pass in props that include media styles and shorthands, get back a flat object of props with the current media styles merged and shorthands expanded. This is an advanced pattern that should be used sparingly, as it will trigger updates on every media query used in the props object. Helpful for more complex components that need to pass down props they are given to children (a common example being the `size` prop, if it's controlling children that also accept size). ```tsx // if props is: // { size: '$2', $sm: { size: '$4' } } // and $sm is active, activeProps will be: // { size: '$4' } // if shorthands like m => margin, then m always expands to margin function MyButton(props) { const activeProps = useProps(props) } ``` You can pass an option to disable the shorthands expansion, and another option to resolve any token strings into their respective theme or token value: ```tsx function MyButton(props) { const activeProps = useProps(props) } ``` useProps takes a second argument, which is the same as useStyle, documented in the next section. ### useStyle Pass in props that include media styles and shorthands, get back a flat style object with the current media styles merged, shorthands expanded, and all theme/token values resolved (into CSS variables on the web or values on native by default). This will remove any non-style values and will by default expand all variants and resolve all values. ```tsx // if props is: // { color: '$background', $sm: { color: '$color' } } // and $sm is active, activeProps will be on web: // { color: 'var(--color)' } // and on native will resolve to the actual theme or token value: // { color: '#fff' } // this resolve behavior can be controlled, see the docs just below. // if shorthands like m => margin, then m expands to margin function MyButton(props) { const style = useStyle(props) } ``` It can take a couple options to control how it resolves values and handles shorthands: ```tsx function MyButton(props) { const style = useStyle(props, { // option to disable the shorthand expansion disableExpandShorthands: true, // option to change how values are resolved // 'auto' (default) resolves to optimized value on all platforms (CSS variable on web, DynamicColor on iOS, not optimized on android) // 'value' resolves to the raw theme/token string on all platforms (the same as useTheme()[name].val) resolveValues: 'value', // pass a Tamagui component to resolve any custom variants: forComponent: CustomComponent, }) } ``` ### usePropsAndStyle Similar to the above two hooks, this returns your fully resolved/merged/media query flattened styles, but instead of returning _just_ props or _just_ style, it returns both of them split out, as well as returning the result of useTheme() and useMedia() that it uses internally: ```tsx function MyButton(props) { const [props, style, theme, media] = usePropsAndStyle(props, opts) // see useStyle to for documentation on opts // we return theme, media as they are used internally already in the hook } ``` ### useThemeName Returns the string name of the current theme. ### useIsTouchDevice SSR-friendly, only true on if native touchable or web touchable device (client side, not server side). ### useDidFinishSSR SSR-friendly, returns true if SSR has completed on the client, false before hydration done. On server it's always false. ### ClientOnly A component that opts its children out of SSR. When wrapped in `ClientOnly`, Tamagui avoids double-renders in various places which results in faster client-side rendering. ```tsx import { ClientOnly } from 'tamagui' // or '@tamagui/core' // Children will render only on the client, skipping SSR entirely // Can be conditionally enabled ``` --- ## Type Helpers ### GetProps Fetches the type of props for a Tamagui component: ```tsx import { Stack, GetProps, styled } from '@tamagui/core' const X = styled(Stack, {}) type XProps = GetProps ``` ### GetRef Fetches the type of a ref for a Tamagui component, or any React component: ```tsx import { Stack, GetRef, styled } from '@tamagui/core' const X = styled(Stack, {}) const MyComponent = () => { const ref = useRef>() return } ``` --- # Source: https://tamagui.dev/docs/core/font-language.md --- title: FontLanguage description: Using custom fonts for each language --- The `FontLanguage` component works with the Tamagui design system, allowing you to define custom fonts per-language. ### Rationale Before `FontLanguage`, you could get custom fonts with some effort. Simply create a `body` font, and a `body_french` font, and switch it out like so on relevant text components: ``. This would work, but having to update every Text component on page with a conditional would be terribly verbose and slow. With `FontLanguage`, you can do: ```tsx Hello world ``` Even better, with `styled`: ```tsx const P = styled(Text, { fontFamily: '$body' })

Hello world

``` On the web, FontLanguage uses CSS Variables to avoid re-renders even when changing languages. ### Usage In your `tamagui.config.ts`, you can add a language variant for any font by adding a suffix with a custom name for that language. Here's a stripped down config showing how you can add the custom `_cn` suffix for a Chinese language font: ```tsx import { createFont, createTamagui, createTokens } from 'tamagui' export default createTamagui({ fonts: { body: createFont({ family: 'Inter, Helvetica, Arial, sans-serif', // ... }), body_cn: createFont({ family: 'Inter-CN', // ... }), }, }) ``` You'll then need to load the `Inter` and `Inter-CN` fonts for the platforms you support. Once you do, you'll get fully typed support for changing any `body` font to `cn` in a component: ```tsx import { FontLanguage, Text } from 'tamagui' // or '@tamagui/core' export default ( 你好 ) ``` The name you choose for the suffix is up to you, and Tamagui will treat any font with a `_` separator as a language variant. To reset your font back to your base `body` font, you can use the reserved key `default`: ```tsx import { FontLanguage, Text } from 'tamagui' // or '@tamagui/core' export default ( 你好 Hello ) ``` --- # Source: https://tamagui.dev/ui/form.md --- title: Form description: A simple form component for native and web. name: form component: Form package: form demoName: Form --- ```tsx hero template=Forms ``` ## Installation Form is already installed in `tamagui`, or you can install it independently: ```bash npm install @tamagui/form ``` ## Anatomy ```tsx import { Form } from 'tamagui' // or '@tamagui/form' export default () => (
{/* ... */} ) ``` For a simpler use case and backwards compat, you can also use it without `Group.Item`, which will just apply borders and spacing based on direct children. Note that Group will detect if any `Group.Item` is inside it, and automatically switch modes. If no Item, it spaces direct children: ```tsx import { Button, XGroup } from 'tamagui' // usage without Item: export default () => ( ) ``` ## Sizing The `size` property will use your tokens to grab the appropriate radius for borderRadius values which it will pass to the first and last child as style props for borderRadius. ```tsx import { Button, XGroup } from 'tamagui' export default () => ( ) ``` ## Disabled The `disabled` property will pass to children ## Group API ### Group `Group`, `XGroup`and`YGroup` extend [YStack](/docs/components/stacks), getting [Tamagui standard props](/docs/intro/props), plus: ### Group.Item Wrap each of `XGroup` or `YGroup`'s children in one of these. It lets Tamagui apply the needed styles to them. Accepts only a `children` prop. --- # Source: https://tamagui.dev/ui/headings.md --- title: Headings description: Heading components that mimic HTML equivalents name: html component: Headings package: text demoName: Headings --- ```tsx hero template=Headings ``` ## Installation Headings is already installed in `tamagui`, or you can install it independently: ```bash npm install @tamagui/text ``` ```tsx import { H1, H2, H3, H4, H5, H6, Heading } from 'tamagui' export default () => ( <>

Heading 1

Heading 2

Heading 3

Heading 4

Heading 5
Heading 6
Heading ) ``` The headings all extend from the base `Heading` component. Note, this is just our own theme for Inter headings, but you can change the styles for any font completely. Tamagui expects for your [font.size](/docs/core/configuration#font-tokens) to have the keys 1-10 so headings work with your font tokens automatically. ## How it works The `Heading` component is defined as follows: ```tsx export const Heading = styled(Paragraph, { tag: 'span', name: 'Heading', accessibilityRole: 'header', fontFamily: '$heading', size: '$8', margin: 0, }) ``` Note that Heading, and H1-H6 all default to the `heading` font family that must be defined in your tamagui.config.ts. Because [Paragraph](/docs/components/text#paragraph) extends [SizableText](/docs/components/text#sizabletext), you get automatic styles based on your font theme. Let's see how `SizableText` defines the size variant, roughly, which gives a good idea of how Tamagui works, and how you could create or change your own headings at a lower level. ```tsx import { Text } from 'tamagui' // or '@tamagui/core' const SizableText = styled(Text, { name: 'SizableText', fontFamily: '$body', color: '$color', variants: { size: { '...fontSize': (val, { font, props }) => { const fontSize = font.size[val] const lineHeight = font.lineHeight[val] const fontWeight = font.weight[val] const letterSpacing = font.letterSpacing[val] const fontStyle = font.style?.[val] const textTransform = font.transform?.[val] return { fontStyle, textTransform, fontWeight, letterSpacing, fontSize, lineHeight, } }, }, }, defaultVariants: { // note tamagui uses a generic "true" token that your sizes should set to be the same as the default on your scale size: '$true', }, }) ``` ## API Reference ### Heading Headings extend [SizableText props](/docs/components/text#sizabletext) inheriting all the [Tamagui standard props](/docs/intro/props). --- # Source: https://tamagui.dev/ui/html-elements.md --- title: HTML Elements description: Render semantic HTML with these elements. name: html-elements component: Layouts --- To assist in creating accessible web apps, the following components are exported, all mapping directly to DOM elements of the lowercase names: - `Section` (`section`) - `Article` (`article`) - `Main` (`main`) - `Header` (`header`) - `Aside` (`aside`) - `Footer` (`footer`) - `Nav` (`nav`) ## Installation It's exported by `tamagui`, or: ```bash npm install @tamagui/elements ``` ## HTML element props All HTML components extend View, inheriting all the [Tamagui standard props](/docs/intro/props). --- # Source: https://tamagui.dev/ui/image.md --- title: Image description: React Native Web Image + Tamagui style props. name: html component: Image package: image demoName: Image --- ```tsx hero template=Image ``` ## Installation Image is already installed in `tamagui`, or you can install it independently: ```bash npm install @tamagui/image ``` ## Usage Note that you need to set `source` like so - the `width` and `height` properties apply as styles around the image, but the actual image needs `source.width` and `source.height` for React Native: ```tsx export default () => ( ) ``` ## API Reference ### Image [Tamagui props](/docs/intro/props) + [React Native Web Image props](https://necolas.github.io/react-native-web/docs/image/). --- # Source: https://tamagui.dev/ui/inputs.md --- title: Input & Textarea name: inputs description: Flexible form fields in styled and unstyled forms. component: Input demoName: Inputs --- ```tsx hero template=Inputs ``` Using the same base component TextInput, from [React Native](https://reactnative.dev/docs/textinput) or [React Native Web](https://necolas.github.io/react-native-web/docs/text-input/), Tamagui simply wraps these components to allow the full set of style props, as well as scaling all the styles up or down using the `size` property, much like Button. ## Installation Input 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