How to use
Button is the pressable primitive nearly everything else in the library builds on — plain actions, form submits, links styled as buttons, and icon-only controls all go through the same component. It renders a native <button> by default and switches to an <a> automatically the moment you pass href, so you never have to choose the element yourself.
import { Button } from "oks-ui";variant sets how much visual weight a button carries: solid (the default) is a filled, high-contrast action; soft is a tinted background for secondary actions that shouldn't compete with a solid primary button nearby; bordered keeps just an outline; ghost has no background or border until hovered; link strips button chrome entirely and reads as an inline text link. color is one of seven semantic roles and works the same way across every variant.
<Button variant="solid" color="primary">Save</Button>
<Button variant="soft" color="default">Cancel</Button>
<Button variant="bordered" color="danger">Delete</Button>
<Button variant="ghost" color="default">Skip</Button>
<Button variant="link" color="primary">Learn more</Button>Pass href and Button renders a real anchor instead of a button element — no wrapping a Button inside a Link and fighting duplicate focus rings. target/rel/download all forward straight to the anchor, and rel defaults to "noopener noreferrer" automatically whenever target="_blank" is set, so external links can't be quietly forgotten. For a client-side router's own Link component, use the polymorphic as prop instead.
<Button href="/pricing" variant="soft">View pricing</Button>
<Button href="https://github.com/oks-ui" target="_blank">GitHub ↗</Button>
// Polymorphic: render as next/link (or any component) instead of <a>/<button>
<Button as={Link} href="/dashboard" color="primary">
Go to dashboard
</Button>isLoading swaps in a spinner (spinnerPlacement controls which side of the label it sits on, or pass your own spinner node) and sets aria-busy — but the button stays focusable and enabled on purpose, so a screen reader user tabbed onto it doesn't lose their place mid-action. Use isDisabled separately when the action genuinely shouldn't be reachable at all; disabling removes it from the tab order and, on an anchor-rendered button, adds aria-disabled since native <a> has no disabled attribute.
<Button isLoading color="primary">Saving…</Button>
<Button isDisabled variant="soft">Unavailable</Button>For a button that's just an icon, set isIconOnly (which switches to a square footprint sized off the current size scale) and always pass an aria-label — there's no visible text for assistive tech to fall back on otherwise.
<Button isIconOnly variant="ghost" aria-label="Close">
<XIcon />
</Button>Button forwards native onClick as usual, but also exposes onPress/onPressStart/onPressEnd/onPressUp/onPressChange for cases that care about the full press lifecycle (press-and-hold interactions, custom ripple-adjacent effects, distinguishing a press that started on the button but was dragged off before release). Reach for plain onClick unless you specifically need one of those finer-grained moments.
All available props for Button. See the full component page for an interactive playground.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Button label/content. |
startContent | ReactNode | — | Content rendered before the label. |
endContent | ReactNode | — | Content rendered after the label. |
spinner | ReactNode | built-in spinner | Overrides the default loading spinner. |
spinnerPlacement | "start" | "end" | start | Where the loading spinner renders relative to the label. |
children
ReactNode
Default: —
Button label/content.
startContent
ReactNode
Default: —
Content rendered before the label.
endContent
ReactNode
Default: —
Content rendered after the label.
spinner
ReactNode
Default: built-in spinner
Overrides the default loading spinner.
spinnerPlacement
"start" | "end"
Default: start
Where the loading spinner renders relative to the label.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "solid" | "soft" | "bordered" | "ghost" | "link" | solid | Visual style variant. |
color | "default" | "primary" | "secondary" | "info" | "success" | "warning" | "danger" | default | Semantic color. |
colorDepth | 50 | 100 | ... | 950 | 500 | Shade depth for the selected color. |
size | "xs" | "xs-sm" | "sm" | "md" | "lg" | "xl" | md | Button size. |
radius | "none" | "xs" | "xs-sm" | "sm" | "md" | "lg" | "full" | md | Border radius. |
shadow | "none" | "xs" | "xs-sm" | "sm" | "md" | "lg" | none | Box-shadow depth. |
variant
"solid" | "soft" | "bordered" | "ghost" | "link"
Default: solid
Visual style variant.
color
"default" | "primary" | "secondary" | "info" | "success" | "warning" | "danger"
Default: default
Semantic color.
colorDepth
50 | 100 | ... | 950
Default: 500
Shade depth for the selected color.
size
"xs" | "xs-sm" | "sm" | "md" | "lg" | "xl"
Default: md
Button size.
radius
"none" | "xs" | "xs-sm" | "sm" | "md" | "lg" | "full"
Default: md
Border radius.
shadow
"none" | "xs" | "xs-sm" | "sm" | "md" | "lg"
Default: none
Box-shadow depth.
| Prop | Type | Default | Description |
|---|---|---|---|
fullWidth | boolean | false | Expands to fill available horizontal space. |
isIconOnly | boolean | false | Renders a square icon button. Requires aria-label. |
fullWidth
boolean
Default: false
Expands to fill available horizontal space.
isIconOnly
boolean
Default: false
Renders a square icon button. Requires aria-label.
| Prop | Type | Default | Description |
|---|---|---|---|
as | ElementType | href ? "a" : "button" | Render as a different element or component. |
href | string | — | Renders as an anchor when set. |
target | string | — | Anchor target. |
rel | string | "noopener noreferrer" when target="_blank" | Anchor rel attribute. |
download | string | boolean | — | Anchor download attribute. |
tooltip | ReactNode | boolean | (Omit<TooltipProps, "children"|"content"> & { content?: ReactNode }) | — | Wraps the button in the built-in Tooltip component when set. A plain value is shorthand content; bare true derives content from aria-label; an object accepts any Tooltip prop plus an optional content override. Omitted entirely by default. |
isDisabled | boolean | false | Disables the button; sets aria-disabled + tabIndex=-1 when rendered as an anchor. |
isLoading | boolean | false | Shows a spinner and sets aria-busy; stays focusable by design. |
as
ElementType
Default: href ? "a" : "button"
Render as a different element or component.
href
string
Default: —
Renders as an anchor when set.
target
string
Default: —
Anchor target.
rel
string
Default: "noopener noreferrer" when target="_blank"
Anchor rel attribute.
download
string | boolean
Default: —
Anchor download attribute.
tooltip
ReactNode | boolean | (Omit<TooltipProps, "children"|"content"> & { content?: ReactNode })
Default: —
Wraps the button in the built-in Tooltip component when set. A plain value is shorthand content; bare true derives content from aria-label; an object accepts any Tooltip prop plus an optional content override. Omitted entirely by default.
isDisabled
boolean
Default: false
Disables the button; sets aria-disabled + tabIndex=-1 when rendered as an anchor.
isLoading
boolean
Default: false
Shows a spinner and sets aria-busy; stays focusable by design.
| Prop | Type | Default | Description |
|---|---|---|---|
disableRipple | boolean | false | Disables the click ripple effect. |
disableAnimation | boolean | false | Disables all transitions/animations, including the ripple. |
disableRipple
boolean
Default: false
Disables the click ripple effect.
disableAnimation
boolean
Default: false
Disables all transitions/animations, including the ripple.
| Prop | Type | Default | Description |
|---|---|---|---|
onPress / onPressStart / onPressEnd / onPressUp / onPressChange | (e) => void | — | Press-style callbacks alongside native onClick. |
onPress / onPressStart / onPressEnd / onPressUp / onPressChange
(e) => void
Default: —
Press-style callbacks alongside native onClick.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Class applied to the root element. |
style | CSSProperties | — | Inline styles for the root element. |
className
string
Default: —
Class applied to the root element.
style
CSSProperties
Default: —
Inline styles for the root element.