Back to Tamagui

Button

code/tamagui.dev/data/docs/components/button/2.0.0.mdx

1.144.49.9 KB
Original Source
<HeroContainer demoMultiple> <ButtonDemo /> </HeroContainer>
tsx

<Highlights features={[ 'Size prop that works on all styles.', 'Place an icon before or after.', 'Control icon size explicitly with iconSize.', 'Theme groups of buttons with Button.Apply.', ]} />

Installation

Button is already installed in tamagui, or you can install it independently:

bash
npm install @tamagui/button

Usage

tsx
import { Button } from 'tamagui'

export default () => <Button>Lorem ipsum</Button>

Sizing

Sizing buttons provides a unique challenge especially for a compiler, because you need to adjust many different properties - not just on the outer frame, but on the text wrapped inside. Tamagui supports adjusting the padding, border radius, font size and icons sizes all in one with the size prop.

tsx
import { Button } from 'tamagui'

export default () => <Button size="$6">Lorem ipsum</Button>

Given your theme defines a size 6, the button will adjust all of the properties appropriately. You can also pass a plain number to get an arbitrary size.

Variants

The Button component supports different visual styles through the variant prop. Currently, the primary available variant is "outlined".

tsx
import { Button, XStack } from 'tamagui'

export default () => (
  <XStack gap="$2">
    <Button>Default</Button>
    <Button variant="outlined">Outlined</Button>
  </XStack>
)

When variant="outlined" is applied, the button typically has a transparent background with a visible border. The exact appearance (border color, hover/press states) is determined by your theme's definitions for an outlined button.

Icon Theming

You can pass icons as either elements or components. If passing components, Tamagui will automatically theme them (passing size). The icon size is determined by the Button's size prop by default.

You can also explicitly set the icon size using the iconSize prop, which accepts a SizeTokens value (e.g., "$2"). The scaleIcon prop can be used to further adjust the size relative to the determined or explicitly set icon size.

When an icon is present, Tamagui automatically adds spacing between the icon and the button's text. 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 () => (
  <>
    <Button icon={Star} size="$5">
      Icon sized by Button
    </Button>
    <Button icon={Star} iconSize="$2" size="$5">
      Icon sized explicitly
    </Button>
  </>
)

You can use the source of Button itself to see in more detail what variants you can override, and how we use this pattern internally to create our Button component.

Group Theming

You can use Button.Apply to theme a group of Buttons using a shared context. This is useful for applying consistent sizing or variants to multiple buttons without passing props to each one individually.

tsx
import { Button, ButtonDemo, YStack } from 'tamagui'

export default () => (
  <YStack gap="$4">
    <Button.Apply size="$2" variant="outlined">
      <Button>Small Outlined 1</Button>
      <Button>Small Outlined 2</Button>
      <Button icon={ButtonDemo}>With Icon</Button>
    </Button.Apply>

    <Button.Apply size="$5">
      <Button>Large 1</Button>
      <Button theme="blue">Large Themed</Button>
    </Button.Apply>
  </YStack>
)

Web Form Props

Button supports all standard HTML <button> attributes for form integration. These props are web-only and ignored on native:

tsx
import { Button, Form } from 'tamagui'

export default () => (
  <Form action="/submit">
    <Button type="submit">Submit Form</Button>
    <Button type="reset">Reset</Button>
    <Button type="button">Regular Button (default)</Button>
    <Button type="submit" formAction="/alternative-endpoint" formMethod="post">
      Submit to Different Endpoint
    </Button>
  </Form>
)
<Notice> Button defaults to `type="button"` to prevent unintended form submissions. Use `type="submit"` explicitly when you want form submission behavior. </Notice>

Text Styling

Button does not support a color prop directly. Instead, use Button.Text for full control over text styling. Combine it with the group prop on Button to coordinate interactive styles between the frame and its children:

tsx
import { Button } from 'tamagui'

export default () => (
  <Button group="btn" bg="pink">
    <Button.Text color="blue" $group-btn-hover={{ color: 'red' }}>
      Hello world
    </Button.Text>
  </Button>
)

The group prop lets any child reference interactive states like $group-btn-hover, $group-btn-press, and $group-btn-focus for precise styling per interaction state.

Creating Your Own Button

Tamagui now has all the features necessary to make creating a custom Button easy enough that you may want to roll your own button. Learn how to do it with our dedicated guide, How to Build a Button.

API Reference

Buttons extend Stack views inheriting all the Tamagui standard props, plus:

<PropsTable data={[ { name: 'size', required: false, type: 'SizeTokens | number', description: Set a size from your theme's size tokens (e.g., "$4") or a specific number. Adjusts padding, font size, and icon sizes., }, { name: 'variant', required: false, type: '"outlined" | undefined', description: 'Applies the "outlined" button style.', }, { name: 'disabled', required: false, type: 'boolean', description: 'If true, the button will be non-interactive and visually disabled. Sets pointerEvents: "none".', }, { name: 'theme', required: false, type: 'string', description: Apply a theme just to the button and its children., }, { name: 'icon', required: false, type: 'React.ReactNode | React.ComponentType<{ color?: string, size?: number }>', description: Pass any React element or a component. Appears before the text. If a component is passed, 'color' and 'size' props are passed to it., }, { name: 'iconAfter', required: false, type: 'React.ReactNode | React.ComponentType<{ color?: string, size?: number }>', description: Pass any React element or a component. Appears after the text. If a component is passed, 'color' and 'size' props are passed to it., }, { name: 'iconSize', required: false, type: 'SizeTokens', description: Explicitly set the size of the icon, overriding the default size derived from the Button's 'size' prop. Uses theme size tokens (e.g., "$2")., }, { name: 'scaleIcon', required: false, type: 'number', description: Scale the icon by this factor. Default is 1. Applied after 'iconSize' or the default size calculation., }, { name: 'circular', required: false, type: boolean, description: Forces a circular button. Applies border radius to make the button a circle., }, { name: 'chromeless', required: false, type: 'boolean | "all"', description: 'Removes default Tamagui visual styles (background, border) for a more minimal appearance, while keeping layout and interactions. If "all", removes hover/press/focus styles too.', }, { name: 'unstyled', required: false, type: boolean, description: Removes all Tamagui default styles, including layout, interactions, and accessibility attributes. Prefer 'chromeless' for removing only visual styles., }, // Web-only form props { name: '// Web Form Props', description: 'The following props are web-only and provide full HTML button form semantics. They are ignored on native.', type: '---', }, { name: 'type', required: false, type: '"button" | "submit" | "reset"', description: 'Web-only. The button type. Defaults to "button" to prevent unintended form submissions.', }, { name: 'formAction', required: false, type: 'string', description: "Web-only. URL for form submission, overrides the form's action.", }, { name: 'formMethod', required: false, type: '"get" | "post"', description: 'Web-only. HTTP method for form submission.', }, { name: 'formEncType', required: false, type: 'string', description: 'Web-only. Encoding type for form data.', }, { name: 'formNoValidate', required: false, type: 'boolean', description: 'Web-only. Bypass form validation when submitting.', }, { name: 'formTarget', required: false, type: 'string', description: 'Web-only. Where to display form response (_self, _blank, etc).', }, { name: 'name', required: false, type: 'string', description: 'Web-only. Name submitted with form data.', }, { name: 'value', required: false, type: 'string', description: 'Web-only. Value submitted with form data.', }, { name: 'popoverTarget', required: false, type: 'string', description: 'Web-only. ID of popover element to control.', }, { name: 'popoverTargetAction', required: false, type: '"hide" | "show" | "toggle"', description: 'Web-only. Action to perform on the popover.', }, // Note about text styling { name: '// Text Styling', description: 'Button does not support color directly. To style text color, use Button.Text with the group prop for interactive states. See the Text Styling section above.', type: '---', }, ]} />