Components

Button

A native <button>, after Base UI's Button. It is type="button" unless you say otherwise, so it submits a form only when asked to. Disabled it leaves the tab order; with focusableWhenDisabled it stays focusable as aria-disabled="true" (a loading state keeps focus where it was) and a tiny script cancels its clicks.

A live demo, with the default theme. Its code
ts
import { Button } from "@lumiose/ui"; // or "@lumiose/ui/button"
import "@lumiose/ui/themes/default.css"; // optional: the default theme

#Anatomy

tsx
<Button>Save</Button>
Part Renders
Button <button type="button">; aria-disabled="true" with focusableWhenDisabled

#API

#Button

Prop Type Default
type string "button" "submit" or "reset" to act on its form.
disabled boolean false Natively disabled: out of the tab order, its clicks ignored.
focusableWhenDisabled boolean false With disabled: it stays focusable as aria-disabled="true", and its clicks, presses, Enter and Space do nothing.

Every other native prop passes through: name, value, form, command, commandfor, popovertarget, id, class, aria-*, onClick.

Differences from Base UI's Button. It is always a <button>: no nativeButton or render. For a link that looks like a button, style an <a> with the same class.

#Example

A save button that keeps focus while it saves, in an island:

Live at the top of the page: an island
tsx
import { Button } from "@lumiose/ui";
import { signal } from "lumiose";

export function SavingButton() {
  const saving = signal(false);
  return (
    <Button
      class="lu-button"
      data-variant="primary"
      disabled={saving()}
      focusableWhenDisabled
      onClick={() => {
        saving.set(true);
        setTimeout(() => saving.set(false), 1500);
      }}
    >
      {saving() ? "Saving…" : "Save"}
    </Button>
  );
}

#Styling

With the default theme, put lu-button on it (data-variant="primary" or data-variant="destructive" for the others): a 36px tall button with a focus ring, faded when :disabled or [aria-disabled="true"].

With your own CSS, style the button and its states: :hover, :focus-visible, :disabled, [aria-disabled="true"].

Button ships no stylesheet: it needs none to work.

#Keyboard and focus

Key Does
Enter / Space Presses it, unless it is disabled.
Tab Moves on. A disabled button is skipped, unless it is focusable when disabled.

#Without JavaScript, and the client script

A native button: it works, submits and resets with no script. The client script (0.2 kB brotli) only cancels the clicks, Enter and Space of an aria-disabled button (one without a role of its own), and keeps its presses (pointerdown, mousedown) and Enter and Space keys from its handlers and its ancestors' bubbling ones, as Base UI does; listeners that capture still see them, and the other keys (Tab, a toolbar's arrows) go on. Without it such a button still acts, so a server page that disables a button until something happens should use disabled alone.

#Browser support

Native <button>: every browser.

  • Toggle: a button that stays pressed.
  • Form: a form whose submit button is a Button.
  • Dialog: a Button with command="show-modal" opens a dialog without JavaScript.