Button
One pill, four variants, and three sizes for every action.
import ButtonRoot from "swshd/Button/Root";ButtonRoot is the action surface: it composes Touchable for behavior and paints with a fill and text role from BUTTON_TOKENS. Add ButtonLabel and ButtonIcon as children, in the order they should appear. Reach for it for any pressable action — submit, cancel, delete, navigate.
Don't use it for sidebar navigation rows — that is SidebarItem.
Each variant paints with one fill role and one ink from BUTTON_TOKENS. Hover and pressed are the fill's own states.
Three heights, each paired with a mono label variant and an icon size. Set iconOnly for a circle with a ButtonIcon child; accessibilityLabel is then required.
Loading
A spinner replaces the label without changing the width. Presses are blocked.
Disabled
Touchable fades every variant to half opacity, including ghost.
Icon only
Set iconOnly and add ButtonIcon. An accessible label is required.
Full width
Stretches to the parent instead of hugging its content.
Link
With href the web host is a real anchor.
Wrap text in ButtonLabel. Write labels in sentence case, 1–4 words ("Book a demo"). Mono renders them uppercase. ButtonIcon can appear before or after the label. ButtonRoot accepts elements, fragments, wrappers, and arrays with conditional entries.
ButtonLabel inherits its foreground color from ButtonRoot. For inline formatting, set nestable and inheritLineHeight on nested Text children.
import ButtonRoot from "swshd/Button/Root";
import ButtonLabel from "swshd/Button/Label";
import ButtonIcon from "swshd/Button/Icon";
import IconPlus from "swshd/icons/IconPlus";
<ButtonRoot variant="secondary" onPress={onAdd}>
<ButtonIcon Icon={IconPlus} />
<ButtonLabel>Add photos</ButtonLabel>
</ButtonRoot>Keyboard
Tab reaches the button and shows the accent focus ring. Enter and Space press a button; with href it is a link, which Enter activates.
Icon-only
Set iconOnly for an icon control and provide an accessibilityLabel. The type requires the accessible name.
Links
With href, web renders a real anchor. A disabled link is aria-disabled: it does not navigate and does not fire onPress.
ButtonRoot
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "primary" | "secondary" | "ghost" | "destructive" | "primary" | Which BUTTON_TOKENS entry paints the pill. |
size | "sm" | "md" | "lg" | "md" | Height, padding, label variant, and icon size, from BUTTON_SIZES. |
children | ReactElement | readonly (ButtonChild | null | undefined | boolean)[] | — | Compose elements or recursive element arrays in display order, including fragments, wrappers, and conditional list entries. Wrap text in ButtonLabel. |
iconOnly | boolean | false | Makes the root a circle. Requires accessibilityLabel and a ButtonIcon child. |
loading | boolean | false | Shows a spinner in place of the content, blocks presses, and fades the pill like disabled. |
disabled | boolean | false | Blocks presses and fades to 0.5 opacity. |
fullWidth | boolean | false | Stretch to the parent's width instead of hugging the content. |
onPress | () => void | — | Fired on press — or on activation from the keyboard. |
href | string | — | Turns the button into a link. In-app paths start with /. |
target | "_blank" | "_self" | "_parent" | "_top" | "framename" | — | Anchor target (web). |
rel | string | — | Anchor rel (web). |
linkUrlScheme | string | — | Deep-link scheme tried before href (native). |
hitSlop | PressableProps["hitSlop"] | — | Extends the touch target (native). |
accessibilityLabel | string | — | Screen-reader name. Required for icon-only buttons. |
style | StyleProp<ViewStyle> | — | The pill surface. |
containerStyle | StyleProp<ViewStyle> | — | The host element. |
testID | string | — | data-testid on web, testID on native. |
ButtonLabel
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | The label, rendered in the root size's mono label variant. Its foreground color always comes from ButtonRoot; there is no color override. |
ButtonIcon
| Prop | Type | Default | Description |
|---|---|---|---|
Icon | IconComponent | — | Glyph from swshd/icons/*. Its size and foreground color come from ButtonRoot. |
| Legacy | SWSHD |
|---|---|
colorVariant="Contrast" / "Primary" | variant="primary" |
"Card" / "Match" | variant="secondary" |
"Hollow" | variant="ghost" |
"Destructive" | variant="destructive" |
"Palette" / "PaletteSecondary" | not carried — album-palette fills stay in the app layer |
sizeVariant="Large" / "Medium" / "Small", "Skinny*", "Mini" | size="lg" / "md" / "sm" |
"Flex" / "FlexLarge" | fullWidth |
"CircleLarge" | iconOnly, size="lg", with a ButtonIcon child |
roundRadius, iconSize, textProps | dropped — pill only; icon and label derive from size |
Intentional differences: pill only; no per-size min/max widths (pass style or fullWidth); hugs content instead of centering; web hover is a token color, not a brightness filter.