Checkbox

Toggle state in forms

Checkbox provides accessible checked and indeterminate states with controlled or uncontrolled state on web and native.

Features

  • Indeterminate state support

  • Accessible, composable, and customizable

  • Sizing with controlled or uncontrolled state

  • Optional native HTML checkbox on web

Installation

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

yarn add @tamagui/checkbox

Usage

// copy-paste: these skins import from files you own. copy each registry item
// below into your app, then adjust the relative import paths to fit.
// components/tamagui/Checkbox.tsx (registry item "checkbox")
// npm dependencies: @tamagui/checkbox @tamagui/core
import { Check } from './components/icons'; // your generated icons, see Lucide Icons
import { Checkbox } from "../components/tamagui/Checkbox";
export default () => <Checkbox size="md">
<Checkbox.Indicator>
<Check />
</Checkbox.Indicator>
</Checkbox>;

Headless usage

The useCheckbox hook provides all the state and accessibility props needed to build a custom checkbox with any styling solution:

yarn add @tamagui/checkbox-headless
import { useCheckbox } from '@tamagui/checkbox-headless'
import { useState } from 'react'
import { Pressable, View } from 'react-native'
function MyCheckbox({ defaultChecked, onCheckedChange, ...props }) {
const [checked, setChecked] = useState(defaultChecked || false)
const { checkboxProps, checkboxRef, bubbleInput } = useCheckbox(
props,
[checked, setChecked],
null
)
return (
<>
<Pressable ref={checkboxRef} {...checkboxProps} style={{ width: 24, height: 24, borderRadius: 4, borderWidth: 2, borderColor: checked ? '#3b82f6' : '#d1d5db', backgroundColor: checked ? '#3b82f6' : 'transparent', justifyContent: 'center', alignItems: 'center', }} >
{checked && <View style={{ width: 12, height: 12, backgroundColor: 'white' }} />}
</Pressable>
{bubbleInput}
</>
)
}

API reference

Checkbox

Checkbox extends View, inheriting all the View props. Sizes come from the shared Sizing ladder.

Props

  • size

    'xs' | 'sm' | 'md' | 'lg' | 'xl'

    A named size ("xs" to "xl", default "md") is a rung in the sizing ladder: the box is the ladder's square derivation at the rung's radius.

  • labelledBy

    string

    Set the aria-labelledby attribute.

  • name

    string

    Equivalent to input name.

  • value

    string

    Give it a value (for use in HTML forms).

  • checked

    boolean

    Control the input.

  • defaultChecked

    boolean

    Uncontrolled default value.

  • required

    boolean

    Sets aria-required.

  • native

    boolean

    Renders native checkbox input on web.

  • onCheckedChange

    (checked: boolean | "indeterminate") => void

    Callback that fires when the checkbox state is changed.

  • unstyled

    boolean

    Removes all default Tamagui styles.

  • activeStyle

    StylePiece

    Styles to apply when the checkbox is checked. Accepts a style() piece.

  • activeTheme

    string | null

    Theme to apply when the checkbox is checked. Set to null for no theme change.

  • Checkbox.Indicator

    Checkbox.Indicator extends View, inheriting all the View props, plus:

    Props

  • activeStyle

    StylePiece

    Styles to apply when the indicator is active. Accepts a style() piece.

  • forceMount

    boolean

    Used to force mounting when more control is needed.

  • useCheckbox

    The useCheckbox hook accepts three arguments:

    const { checkboxProps, checkboxRef, bubbleInput } = useCheckbox(
    props, // CheckboxProps
    state, // [checked: CheckedState, setChecked: (checked: CheckedState) => void]
    ref // React.Ref
    )

    CheckedState

    The checkbox supports three states:

    • true - checked
    • false - unchecked
    • 'indeterminate' - indeterminate/mixed state (useful for “select all” patterns)

    Props (first argument)

    Props

  • labelledBy

    string

    Set aria-labelledby for accessibility.

  • disabled

    boolean

    Whether the checkbox is disabled.

  • name

    string

    Form input name for the hidden input.

  • value

    string

    Default: 

    "on"

    Form input value.

  • required

    boolean

    Whether the checkbox is required in a form.

  • onCheckedChange

    (checked: CheckedState) => void

    Called when checked state changes.

  • onPress

    (event) => void

    Called when checkbox is pressed (composed with internal handler).

  • State (second argument)

    A tuple of [checked, setChecked] where:

    • checked: Current state (boolean | 'indeterminate')
    • setChecked: React state setter function

    Return value

    PropertyTypeDescription
    checkboxPropsobjectProps to spread on your checkbox element (role, aria-checked, onPress, etc.)
    checkboxRefRefComposed ref to attach to your checkbox element
    bubbleInputReactNode | nullHidden input for form compatibility (render as sibling, web only)
    Property
    checkboxProps
    Type
    object
    Description
    Props to spread on your checkbox element (role, aria-checked, onPress, etc.)
    Property
    checkboxRef
    Type
    Ref
    Description
    Composed ref to attach to your checkbox element
    Property
    bubbleInput
    Type
    ReactNode | null
    Description
    Hidden input for form compatibility (render as sibling, web only)

    Source

    v2-look Checkbox: token-based sizing, theme background/border/focus styling, disabled dimming, and a centered indicator over the unstyled @tamagui/ui Checkbox behavior. This is the exact source the registry ships — copy it into your app and the examples above import from your copy.

    components/tamagui/Checkbox.tsx
    import { Checkbox as CheckboxBehavior } from '@tamagui/checkbox' import { type ComponentSize, type GetProps, resolveSizing, styled, withStaticProperties, } from '@tamagui/core' export type CheckboxSize = ComponentSize | boolean // the box reads as a control next to its label: the ladder's square // derivation at the rung's radius. RadioGroup.tsx and Switch.tsx use the same // heights so the three read as one weight at one size const getCheckboxSize = styled.dynamic<CheckboxSize>((val, env) => { const sizing = resolveSizing(val, env) if (!sizing) return return { width: sizing.square, height: sizing.square, borderRadius: sizing.radius, } }) export const CheckboxFrame = styled(CheckboxBehavior, { displayName: 'Checkbox', // checked swaps the whole frame onto the brand theme, so the fill, the border // and the check glyph (icons read theme.color, they do not inherit CSS color) // all move together. the same convention drives Switch and ToggleGroup.Item. activeTheme: 'brand', alignItems: 'center', justifyContent: 'center', backgroundColor: 'background press:background-press', borderColor: 'border-color hover:border-color-hover press:border-color-press', borderWidth: 1, outlineColor: 'focus-visible:outline-color', outlineStyle: 'focus-visible:solid', outlineWidth: 'focus-visible:2px', variants: { size: getCheckboxSize, disabled: { true: { cursor: 'not-allowed', opacity: 0.45, }, }, } as const, defaultVariants: { size: 'md', }, }) export const CheckboxIndicator = styled(CheckboxBehavior.Indicator, { displayName: 'CheckboxIndicator', alignItems: 'center', justifyContent: 'center', }) export const Checkbox = withStaticProperties(CheckboxFrame, { Indicator: CheckboxIndicator, }) export type CheckboxProps = GetProps<typeof Checkbox>

    Dependencies

    yarn add @tamagui/checkbox @tamagui/core

    Expects theme tokens: background, background-press, border-color, border-color-hover, border-color-press, outline-color.

    Need raw behavior without any skin? tamagui/unstyled re-exports the @tamagui/ui primitives (advanced).