# Dialog
> Modal invite dialog on the native dialog element: focus is trapped, Escape closes it, and pixels fly from the trigger to build the panel.
- Element: `<hf-dialog>`
- React: `import { HfDialog } from "@/components/lumesec/hf-dialog"`
- Collection: Pixel HD (https://elements.lumesec.ai/components/pixel-hd)
- Registry item: https://elements.lumesec.ai/r/hf-dialog.json
- Page: https://elements.lumesec.ai/components/pixel-hd/dialog



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

```html
<hf-dialog label="Invite teammates" heading="Invite teammates"></hf-dialog>
```

## 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-dialog
```

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-dialog.json
```

## Usage

React:

```tsx
import { HfDialog } from "@/components/lumesec/hf-dialog";

export function Example() {
  return (
    <HfDialog label="Invite teammates" heading="Invite teammates" />
  );
}
```

HTML:

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

<hf-dialog label="Invite teammates" heading="Invite teammates"></hf-dialog>
```

## Behaviour

A real modal dialog: it traps focus, closes on Escape and returns focus. Opening it, its pixels fly out of the button and assemble the panel over a dithered backdrop; closing sends them back.

## API reference

### Attributes

| Attribute     | React prop    | Type     | Default                                                   | Description                                                       |
| ------------- | ------------- | -------- | --------------------------------------------------------- | ----------------------------------------------------------------- |
| `label`       | `label`       | `string` | `Invite teammates`                                        | Text of the trigger button. Read once on connect.                 |
| `heading`     | `heading`     | `string` | `Invite teammates`                                        | Dialog title, which also labels the dialog. Read once on connect. |
| `description` | `description` | `string` | `They’ll get an email with a link to join the workspace.` | Text under the title. Read once on connect.                       |

### Events

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

| Event   | React prop | Detail                                                                 | Description                                                                                                                                                                                                                                                                   |
| ------- | ---------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `open`  | `onOpen`   | `{}`                                                                   | Fires when the dialog opens.                                                                                                                                                                                                                                                  |
| `close` | `onClose`  | `{ returnValue: string \| undefined, emails?: string, role?: string }` | Fires after the dialog closes. `returnValue` is `send` with the form's `emails` and `role`, `cancel` for Cancel, Escape or a backdrop click, an empty string for the close button, or the argument passed to `hide()`; it is `undefined` when `hide()` is called without one. |

### Methods

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

| Method                       | Description                                                                                                                        |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `show()`                     | Opens the dialog. Ignored unless it is closed.                                                                                     |
| `hide(returnValue?: string)` | Closes the dialog, returns focus to the trigger and passes `returnValue` to `close`. Ignored unless the dialog is open or opening. |

## Keyboard

| Keys   | Action                                                                   |
| ------ | ------------------------------------------------------------------------ |
| Escape | Close the dialog with `returnValue` `cancel`.                            |
| Enter  | In the email field: submit the form and close with `returnValue` `send`. |

## Accessibility

* The trigger button has `aria-haspopup="dialog"`.
* The panel is a native `<dialog>` opened with `showModal()` and labelled by its heading, so the browser traps focus and makes the rest of the page inert.
* Focus moves to the email field when the panel appears and returns to the trigger after closing.
* The close button has `aria-label="Close"`, and the form fields are wrapped in `<label>` elements.
* The backdrop and flying pixels are drawn on an `aria-hidden` canvas.
* Reduced motion: no pixels fly between the button and the panel, the dithered backdrop appears at full strength at once, and the panel appears and disappears at once, without the delay or its fade and scale transition.

## 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 `--border`, `--card`, `--foreground`, `--lumesec`, `--lumesec-foreground`, `--muted` and `--muted-foreground`.

To restyle only LumeSec elements, set the matching `--ui-*` overrides: `--ui-accent`, `--ui-border`, `--ui-fg`, `--ui-muted`, `--ui-on-accent`, `--ui-raised` and `--ui-surface`.

## Notes

* The content is a fixed invite form with an email field and a Member, Admin or Viewer role; only `label`, `heading` and `description` can be changed.
* The element is not form-associated and its inner form is not sent anywhere; read the values from the `close` event.
* The panel is up to 420px wide and centred in the viewport.


