# or
yarn add @zag-js/dialog @zag-js/react
```

## Anatomy

To use the dialog component correctly, you'll need to understand its anatomy and
how we name its parts.

> Each part includes a `data-part` attribute to help identify them in the DOM.



## Usage

First, import the dialog package into your project

```jsx
import * as dialog from "@zag-js/dialog"
```

The dialog package exports two key functions:

- `machine` â The state machine logic for the dialog widget as described in
  WAI-ARIA specification.
- `connect` â The function that translates the machine's state to JSX attributes
  and event handlers.

> You'll need to provide a unique `id` to the `useMachine` hook. This is used to
> ensure that every part has a unique identifier.

Next, import the required hooks and functions for your framework and use the
dialog machine in your project ð¥

```tsx
import * as dialog from "@zag-js/dialog"
import { useMachine, normalizeProps, Portal } from "@zag-js/react"

export function Dialog() {
  const service = useMachine(dialog.machine, { id: "1" })

  const api = dialog.connect(service, normalizeProps)

  return (
    <>
      <button {...api.getTriggerProps()}>Open Dialog</button>
      {api.open && (
        <Portal>
          <div {...api.getBackdropProps()} />
          <div {...api.getPositionerProps()}>
            <div {...api.getContentProps()}>
              <h2 {...api.getTitleProps()}>Edit profile</h2>
              <p {...api.getDescriptionProps()}>
                Make changes to your profile here. Click save when you are done.
              </p>
              <div>
                <input placeholder="Enter name..." />
                <button>Save</button>
              </div>
              <button {...api.getCloseTriggerProps()}>Close</button>
            </div>
          </div>
        </Portal>
      )}
    </>
  )
}
```

### Managing focus within the dialog

When the dialog opens, it automatically sets focus on the first focusable
elements and traps focus within it, so that tabbing is constrained to it.

To control the element that should receive focus on open, pass the
`initialFocusEl` context (which can be an element or a function that returns an
element)

```jsx {3,6,13}
export function Dialog() {
  // initial focused element ref
  const inputRef = useRef(null)

  const service = useMachine(dialog.machine, {
    initialFocusEl: () => inputRef.current,
  })

  // ...

  return (
    //...
    <input ref={inputRef} />
    // ...
  )
}
```

To set the element that receives focus when the dialog closes, pass the
`finalFocusEl` in the similar fashion as shown above.

### Closing the dialog on interaction outside

By default, the dialog closes when you click its overlay. You can set
`closeOnInteractOutside` to `false` if you want the modal to stay visible.

```jsx {2}
const service = useMachine(dialog.machine, {
  closeOnInteractOutside: false,
})
```

You can also customize the behavior by passing a function to the
`onInteractOutside` context and calling `event.preventDefault()`

```jsx {2-7}
const service = useMachine(dialog.machine, {
  onInteractOutside(event) {
    const target = event.target
    if (target?.closest("<selector>")) {
      return event.preventDefault()
    }
  },
})
```

### Listening for open state changes

When the dialog is opened or closed, the `onOpenChange` callback is invoked.

```jsx {2-7}
const service = useMachine(dialog.machine, {
  onOpenChange(details) {
    // details => { open: boolean }
    console.log("open:", details.open)
  },
})
```

### Controlled dialog

To control the dialog's open state, pass the `open` and `onOpenChange`
properties.

```tsx
import { useState } from "react"

export function ControlledDialog() {
  const [open, setOpen] = useState(false)

  const service = useMachine(dialog.machine, {
    open,
    onOpenChange(details) {
      setOpen(details.open)
    },
  })

  return (
    // ...
  )
}
```

### Controlling the scroll behavior

When the dialog is open, it prevents scrolling on the `body` element. To disable
this behavior, set the `preventScroll` context to `false`.

```jsx {2}
const service = useMachine(dialog.machine, {
  preventScroll: false,
})
```

### Creating an alert dialog

The dialog has support for dialog and alert dialog roles. It's set to `dialog`
by default. To change it's role, pass the `role: alertdialog` property to the
machine's context.

That's it! Now you have an alert dialog.

```jsx {2}
const service = useMachine(dialog.machine, {
  role: "alertdialog",
})
```

> By definition, an alert dialog will contain two or more action buttons. We
> recommended setting focus to the least destructive action via `initialFocusEl`

## Styling guide

Earlier, we mentioned that each accordion part has a `data-part` attribute added
to them to select and style them in the DOM.

```css
[data-part="trigger"] {
  /* styles for the trigger element */
}

[data-part="backdrop"] {
  /* styles for the backdrop element */
}

[data-part="positioner"] {
  /* styles for the positioner element */
}

[data-part="content"] {
  /* styles for the content element */
}

[data-part="title"] {
  /* styles for the title element */
}

[data-part="description"] {
  /* styles for the description element */
}

[data-part="close-trigger"] {
  /* styles for the close trigger element */
}
```

### Open and closed state

The dialog has two states: `open` and `closed`. You can use the `data-state`
attribute to style the dialog or trigger based on its state.

```css
[data-part="content"][data-state="open|closed"] {
  /* styles for the open state */
}

[data-part="trigger"][data-state="open|closed"] {
  /* styles for the open state */
}
```

### Nested dialogs

When dialogs are nested (a dialog opened from within another dialog), the layer
stack automatically applies data attributes to help create visual hierarchy look

- `data-nested` - Applied to nested dialogs
- `data-has-nested` - Applied to dialogs that have nested dialogs open
- `--nested-layer-count` - CSS variable indicating the number of nested dialogs

```css
/* Scale down parent dialogs when they have nested children */
[data-part="content"][data-has-nested] {
  transform: scale(calc(1 - var(--nested-layer-count) * 0.05));
  transition: transform 0.2s ease-in-out;
}

/* Style nested dialogs differently */
[data-part="content"][data-nested] {
  border: 2px solid var(--accent-color);
}

/* Create depth effect using backdrop opacity */
[data-part="backdrop"][data-has-nested] {
  opacity: calc(0.4 + var(--nested-layer-count) * 0.1);
}
```

## Methods and Properties

### Machine Context

The dialog machine exposes the following context properties:

**`ids`**
Type: `Partial<{ trigger: string; positioner: string; backdrop: string; content: string; closeTrigger: string; title: string; description: string; }>`
Description: The ids of the elements in the dialog. Useful for composition.

**`trapFocus`**
Type: `boolean`
Description: Whether to trap focus inside the dialog when it's opened

**`preventScroll`**
Type: `boolean`
Description: Whether to prevent scrolling behind the dialog when it's opened

**`modal`**
Type: `boolean`
Description: Whether to prevent pointer interaction outside the element and hide all content below it

**`initialFocusEl`**
Type: `() => HTMLElement`
Description: Element to receive focus when the dialog is opened

**`finalFocusEl`**
Type: `() => HTMLElement`
Description: Element to receive focus when the dialog is closed

**`restoreFocus`**
Type: `boolean`
Description: Whether to restore focus to the element that had focus before the dialog was opened

**`closeOnInteractOutside`**
Type: `boolean`
Description: Whether to close the dialog when the outside is clicked

**`closeOnEscape`**
Type: `boolean`
Description: Whether to close the dialog when the escape key is pressed

**`aria-label`**
Type: `string`
Description: Human readable label for the dialog, in event the dialog title is not rendered

**`role`**
Type: `"dialog" | "alertdialog"`
Description: The dialog's role

**`open`**
Type: `boolean`
Description: The controlled open state of the dialog

**`defaultOpen`**
Type: `boolean`
Description: The initial open state of the dialog when rendered.
Use when you don't need to control the open state of the dialog.

**`onOpenChange`**
Type: `(details: OpenChangeDetails) => void`
Description: Function to call when the dialog's open state changes

**`dir`**
Type: `"ltr" | "rtl"`
Description: The document's text/writing direction.

**`id`**
Type: `string`
Description: The unique identifier of the machine.

**`getRootNode`**
Type: `() => Node | ShadowRoot | Document`
Description: A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.

**`onEscapeKeyDown`**
Type: `(event: KeyboardEvent) => void`
Description: Function called when the escape key is pressed

**`onRequestDismiss`**
Type: `(event: LayerDismissEvent) => void`
Description: Function called when this layer is closed due to a parent layer being closed

**`onPointerDownOutside`**
Type: `(event: PointerDownOutsideEvent) => void`
Description: Function called when the pointer is pressed down outside the component

**`onFocusOutside`**
Type: `(event: FocusOutsideEvent) => void`
Description: Function called when the focus is moved outside the component

**`onInteractOutside`**
Type: `(event: InteractOutsideEvent) => void`
Description: Function called when an interaction happens outside the component

**`persistentElements`**
Type: `(() => Element)[]`
Description: Returns the persistent elements that:
- should not have pointer-events disabled
- should not trigger the dismiss event

### Machine API

The dialog `api` exposes the following methods:

**`open`**
Type: `boolean`
Description: Whether the dialog is open

**`setOpen`**
Type: `(open: boolean) => void`
Description: Function to open or close the dialog

### Data Attributes

**`Trigger`**

**`data-scope`**: dialog
**`data-part`**: trigger
**`data-state`**: "open" | "closed"

**`Backdrop`**

**`data-scope`**: dialog
**`data-part`**: backdrop
**`data-state`**: "open" | "closed"

**`Content`**

**`data-scope`**: dialog
**`data-part`**: content
**`data-state`**: "open" | "closed"
**`data-nested`**: dialog
**`data-has-nested`**: dialog

### CSS Variables

<CssVarTable name="dialog" />

## Accessibility

Adheres to the
[Alert and Message Dialogs WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/alertdialog).

### Keyboard Interactions

**`Enter`**
Description: When focus is on the trigger, opens the dialog.

**`Tab`**
Description: Moves focus to the next focusable element within the content. Focus is trapped within the dialog.

**`Shift + Tab`**
Description: Moves focus to the previous focusable element. Focus is trapped within the dialog.

**`Esc`**
Description: Closes the dialog and moves focus to trigger or the defined final focus element
Editable is an input field used for editing a single line of text. It renders as
static text and transforms into a text input field when then edit interaction is
triggered (click, focus, or double-click).

## Resources


[Latest version: v1.33.1](https://www.npmjs.com/package/@zag-js/editable)
[Logic Visualizer](https://zag-visualizer.vercel.app/editable)
[Source Code](https://github.com/chakra-ui/zag/tree/main/packages/machines/editable)



**Features**

- Use custom controls for the editable
- Pressing `Enter` commits the input value
- Pressing `Esc` reverts the value
- Activate edit mode by double-clicking or focusing on the preview text
- Auto-resize input to fit content

## Installation

To use the editable machine in your project, run the following command in your
command line:

```bash
npm install @zag-js/editable @zag-js/react