> For the complete documentation index, see [llms.txt](https://docs.nickarce.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nickarce.com/etch-drawer/customization/behavior.md).

# Behavior

## Positioning and direction

The drawer can open from any edge. Set the **Open Direction** prop to control the entry point. Each direction uses its own CSS transforms and border-radius rules.

| Direction            | Behavior                                                    |
| -------------------- | ----------------------------------------------------------- |
| **Bottom** (default) | Slides up, rounded top corners, max-height capped           |
| **Top**              | Slides down, rounded bottom corners, accounts for admin bar |
| **Left**             | Slides in from the left, full-height with rounded corners   |
| **Right**            | Slides in from the right, full-height with rounded corners  |

## Drag-to-close

On open drawers, a pointer drag in the closing direction moves the drawer and dims the overlay proportionally. Releasing past the close threshold (25% of the drawer dimension) closes it — otherwise it snaps back.

* **Velocity detection** — fast swipes close immediately regardless of distance
* **Over-drag dampening** — dragging past the open position applies logarithmic resistance
* **Scroll awareness** — dragging is suppressed for 100ms after scrolling inside the drawer body, preventing scroll-to-close conflicts
* **Handle-only mode** — restrict drag to the `.c-drawer__handle` element with the `handleOnly` option
* **No-drag mode** — disable swipe-to-close entirely with the **Disable Drag to Close** prop
* `cursor: grabbing` is applied globally during drag via `.c-drawer--dragging`

## Snap points

Vertical drawers (top or bottom) can rest at multiple heights instead of just open or closed. Add `data-snap-point` to any element inside the drawer body and the drawer will snap to that element's edge as the user drags.

```html
<div data-snap-point="bottom">Quick preview</div>
<div data-snap-point="bottom">Details</div>
<div data-snap-point="top">Full content</div>
```

Use `"top"` to snap to the element's top edge, `"bottom"` to snap to its bottom edge. The drawer opens to the smallest snap point first, and dragging below it closes the drawer. Snap points are ignored for left/right drawers.

### Snap navigation buttons

Add `data-snap-to` to any button inside the drawer to step between snap points on click — useful for discoverability and for visitors who won't drag.

```html
<button data-snap-to="next">Expand</button>
<button data-snap-to="previous">Collapse</button>
```

* `"next"` expands to the next-larger snap point. `"previous"` collapses to the next-smaller one.
* At the extremes the button does nothing — `"next"` no-ops at full height, `"previous"` no-ops at the smallest snap point. It never closes the drawer.
* Use a real `<button>` element. The component does not synthesize keyboard or focus behavior, so a `<div>` would not be operable by keyboard or screen-reader users.
* The button's availability is reflected with `aria-disabled` at the extremes. Style the inactive state with `[data-snap-to][aria-disabled="true"]` if so you desire.
* On non-snap drawers (no `data-snap-point` elements, or left/right direction) the button is ignored — it's inert markup.

## Nested drawers

You can open a drawer from inside another drawer. When this happens, the parent scales back slightly while the child opens on top, then restores when the child closes.

{% stepper %}
{% step %}

### Add a Drawer component to the page

This is your parent drawer.
{% endstep %}

{% step %}

### Inside the **body** of that drawer, insert a second Drawer

This is your child drawer.
{% endstep %}

{% step %}

### Give the child drawer its own **Unique ID**

{% endstep %}

{% step %}

### Add a button inside the parent drawer's body

Set the child's **Open Trigger Selector** to match that button.
{% endstep %}

{% step %}

### The component handles everything else

The child drawer is moved to the correct position, the parent scales back on open, and focus stays within the active drawer.
{% endstep %}
{% endstepper %}

A few things to keep in mind:

* Passive drawers cannot be nested — they don't participate in the stack.
* The child drawer gets its own close gesture and close button. Closing it returns the parent to full size.
* You can nest multiple levels deep, but one or two is the practical limit for usability.

## Passive mode

Passive mode renders the drawer as a non-modal notification bar. It has no overlay, cannot trap focus, and does not lock body scroll.

* Overlay is hidden (CSS managed), body scroll is not locked
* Click outside does not close — only drag or a close button dismisses it
* Trigger elements do not receive `aria-expanded` updates
* `pointer-events: none` on the wrapper lets users interact with content beneath
* Ideal for bottom-sheet notifications that don't demand immediate attention

Enable with the **Passive Mode** prop or the `passive` constructor option.

## Auto-open and persistence

Drawers can open automatically on page load with configurable delay and storage-backed frequency control.

| Frequency option  | Behavior                                                   |
| ----------------- | ---------------------------------------------------------- |
| `every-visit`     | Always show (no persistence)                               |
| `until-dismissed` | Show until the user closes it, then never again            |
| `once`            | Show one time only (recorded on open)                      |
| `after-delay`     | Re-show after a configurable duration since last dismissal |

Duration strings accept `30s`, `2h`, `7d`, or bare numbers (treated as hours). All persistence uses `localStorage` with keys namespaced under `etch-drawer-`.

Configure with the **Auto Open**, **Auto Open Delay**, **Auto Open Reshow**, and **Auto Open Reshow Delay** props.

## Etch builder integration

Inside the Etch visual builder iframe, the Drawer disables all gesture handling and event binding. The builder controls open/close via the **Show In Builder** prop, which toggles visibility on the wrapper element through a `MutationObserver`.

* No drag, no pointer events, no keyboard bindings
* CSS rules handle visibility from the prop value
* The open/close class toggle still synchronizes `data-state` for preview rendering


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.nickarce.com/etch-drawer/customization/behavior.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
