Triggers an action or event, such as submitting a form or opening a dialog.
import { Button } from "@rdloom/react";
export default function ButtonVariantsExample() {
return (
<div className="flex flex-wrap gap-3">
<Button>Save</Button>
<Button variant="secondary">Cancel</Button>
<Button variant="ghost">Skip</Button>
<Button variant="danger">Delete</Button>
</div>
);
}Installation
npx rdloom add buttonCopies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes. It needs react-aria-components; add --install to install them.
Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/button.jsonWorks, but without upgrade tracking.
Usage
import { Button } from "@rdloom/react";
<div className="flex flex-wrap gap-3">
<Button>Save</Button>
<Button variant="secondary">Cancel</Button>
<Button variant="ghost">Skip</Button>
<Button variant="danger">Delete</Button>
</div>Sizes
import { Button } from "@rdloom/react";
export default function ButtonSizesExample() {
return (
<div className="flex flex-wrap items-center gap-3">
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
</div>
);
}Loading
import { useState } from "react";
import { Button } from "@rdloom/react";
export default function ButtonLoadingExample() {
const [saving, setSaving] = useState(false);
return (
<Button
isLoading={saving}
onPress={() => {
setSaving(true);
setTimeout(() => setSaving(false), 2000);
}}
>
{saving ? "Saving" : "Save changes"}
</Button>
);
}Disabled
import { Button } from "@rdloom/react";
export default function ButtonDisabledExample() {
return (
<div className="flex flex-wrap gap-3">
<Button isDisabled>Publish</Button>
<Button variant="secondary" isDisabled>
Archive
</Button>
</div>
);
}With icon
import { Button } from "@rdloom/react";
function PlusIcon() {
return (
<svg aria-hidden="true" viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M8 3v10M3 8h10" />
</svg>
);
}
export default function ButtonWithIconExample() {
return (
<div className="flex flex-wrap gap-3">
<Button>
<PlusIcon /> New project
</Button>
{/* Icon-only buttons need a label for screen readers. */}
<Button variant="ghost" aria-label="Add item">
<PlusIcon />
</Button>
</div>
);
}API Reference
Defined by the spec. Components also accept the props of the React Aria component they wrap.
| Prop | Type | Default |
|---|---|---|
variantVisual emphasis of the button. | "primary" | "secondary" | "ghost" | "danger" | "primary" |
sizeHeight, padding and font size. | "sm" | "md" | "lg" | "md" |
isDisabledPrevents interaction and dims the button. | boolean | false |
isLoadingShows a spinner and blocks presses. The button stays focusable, is marked aria-disabled, and the pending state is announced. | boolean | false |
childrenrequiredButton label. Icon-only buttons must pass aria-label instead. | node | none |
onPressCalled when the button is pressed by mouse, touch or keyboard. | () => void | none |
Accessibility
Role button, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.
Keyboard
- Enter activates
- Space activates
Screen readers announce
- Announced as a button with its visible label
- An icon-only button (the ⚙ in the playground) announces its aria-label, not the icon
- Disabled: announced as unavailable or dimmed
- Loading: announced as unavailable, and the busy state is spoken when loading starts
What your code must do
- Must have visible text or an aria-label
- Focus ring must meet 3:1 contrast against its background
Guidelines
Use it when
- Performing an action on the current page
- Submitting a form
Avoid it when
- Navigating to another page: use Link
Don't
- More than one primary button in the same area
- Vague labels like 'Click here'
Design tokens
The semantic tokens this component uses. Change them once and every component follows; see Design tokens.
--rd-color-action-primary--rd-color-action-primary-hover--rd-color-action-on-primary--rd-color-action-danger--rd-color-surface-subtle--rd-color-border-default--rd-color-text-default--rd-color-focus-ring--rd-radius-control--rd-space-control-x