# Button
> Dot-matrix button with a pointer light and press ripples; `run(fn)` shows loading, success and error states around a promise.
- Element: `<hf-button>`
- React: `import { HfButton } from "@/components/lumesec/hf-button"`
- Collection: Pixel HD (https://elements.lumesec.ai/components/pixel-hd)
- Registry item: https://elements.lumesec.ai/r/hf-button.json
- Page: https://elements.lumesec.ai/components/pixel-hd/button



Live preview: https://elements.lumesec.ai/view/hf-button

```html
<hf-button demo="ok" success-text="Generated">Generate</hf-button>
<hf-button variant="danger" demo="error">Delete</hf-button>
```

## Playground

Change a prop and the component updates. Props marked live animate to the new value; the others rebuild the element.

## Installation

```bash
npx shadcn@latest add @lumesec/hf-button
```

First time with the @lumesec registry? Register it once, or install by URL:

```bash
npx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.json
npx shadcn@latest add https://elements.lumesec.ai/r/hf-button.json
```

## Usage

React:

```tsx
import { HfButton } from "@/components/lumesec/hf-button";

export function Example() {
  return (
    <>
      <HfButton demo="ok" successText="Generated">Generate</HfButton>
      <HfButton variant="danger" demo="error">Delete</HfButton>
    </>
  );
}
```

HTML:

```html
<script type="module" src="https://elements.lumesec.ai/cdn/hf-button.js"></script>

<hf-button demo="ok" success-text="Generated">Generate</hf-button>
<hf-button variant="danger" demo="error">Delete</hf-button>
```

## Behaviour

Noise-lit surface, pointer light, ripples on press, a flowing loading field and a sweep on success. `run(fn)` takes a promise and handles all three states.

## API reference

### Attributes

| Attribute      | React prop    | Type     | Default     | Description                                                                                                                                               |
| -------------- | ------------- | -------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `variant`      | `variant`     | `danger` | —           | Set to `danger` for the red colour scheme. Without it the accent colour is used. Read directly by CSS and the canvas, so changes apply on the next frame. |
| `loading-text` | `loadingText` | `string` | `Working…`  | Label shown while the promise passed to `run()` is pending.                                                                                               |
| `success-text` | `successText` | `string` | `Done`      | Label shown for 1.7 s after the promise resolves.                                                                                                         |
| `error-text`   | `errorText`   | `string` | `Try again` | Label shown for 1.7 s after the promise rejects.                                                                                                          |
| `type`         | `type`        | `string` | —           | Set to `submit` to call `requestSubmit()` on the owning form when clicked. Ignored when `demo` is set.                                                    |
| `demo`         | `demo`        | `string` | —           | Makes a click run a simulated 1.5 s task. `error` makes it fail; any other non-empty value makes it succeed.                                              |

### Events

Events bubble and cross the shadow boundary unless the description says otherwise.

| Event     | React prop  | Detail | Description                                        |
| --------- | ----------- | ------ | -------------------------------------------------- |
| `start`   | `onStart`   | `{}`   | Fires when `run()` enters the loading state.       |
| `success` | `onSuccess` | `{}`   | Fires when the promise passed to `run()` resolves. |
| `error`   | `onError`   | `{}`   | Fires when the promise passed to `run()` rejects.  |

### Methods

Call them on the element, for example through a React ref.

| Method                                              | Description                                                                                                                                                            |
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `run(fn: () => Promise<unknown>): Promise<unknown>` | Shows the loading state while the promise runs, then success or error for 1.7 s before returning to the label. Resolves with the promise value and rethrows its error. |

## Accessibility

* Renders a native `<button type="button">` in the shadow root, so Enter and Space activate it.
* The label sits in an `aria-live="polite"` region, so the loading, success and error text is announced.
* Sets `aria-busy` on the inner button: `true` while loading, `false` otherwise.
* Clicks during loading are stopped at the inner button and do not reach the host.
* Form-associated but submits no value of its own. With `type="submit"` a click calls `requestSubmit()` on the owning form.
* Reduced motion: the noise and loading fields are static, the label swaps without rolling, the error shake is skipped and the canvas redraws only on pointer movement or press.

## Theming

The element reads your shadcn theme tokens through its shadow root, so light and dark follow your theme. The accent comes from `--lumesec`. See [Theming](/docs/theming).

This component reads `--destructive`, `--foreground` and `--lumesec`.

To restyle only LumeSec elements, set the matching `--ui-*` overrides: `--ui-accent`, `--ui-danger` and `--ui-fg`.

## Notes

* The label is the element's text content, read once on first connect (default `Generate`). Later text changes are not picked up.


