# `PhiaUi.Components.Resizable`
[🔗](https://github.com/charlenopires/PhiaUI/blob/v0.1.17/lib/phia_ui/components/layout/resizable.ex#L1)

Drag-to-resize split panel component.

Provides `resizable/1`, `resizable_panel/1`, and `resizable_handle/1`
sub-components that together create a resizable split-pane layout. The
`PhiaResizable` JavaScript hook handles mouse drag, touch drag, and
keyboard arrow-key resizing with configurable min/max size clamping.

## Sub-components

| Component           | Element | Purpose                                               |
|---------------------|---------|-------------------------------------------------------|
| `resizable/1`       | `<div>` | Flex container with the `PhiaResizable` hook attached |
| `resizable_panel/1` | `<div>` | Individual panel sized via CSS `flex`                 |
| `resizable_handle/1`| `<div>` | Drag handle between panels (keyboard focusable)       |

## Hook setup

Register the `PhiaResizable` hook in your LiveSocket before using this
component:

    // assets/js/app.js
    import PhiaResizable from "./hooks/resizable"

    let liveSocket = new LiveSocket("/live", Socket, {
      hooks: { PhiaResizable }
    })

## Horizontal split (default)

Side-by-side panels, the most common layout for code editors, detail/list
splits, and side-by-side comparisons:

    <.resizable class="h-[400px]">
      <.resizable_panel default_size={50} min_size={20}>
        <div class="h-full p-4">Left panel</div>
      </.resizable_panel>
      <.resizable_handle />
      <.resizable_panel default_size={50} min_size={20}>
        <div class="h-full p-4">Right panel</div>
      </.resizable_panel>
    </.resizable>

## Vertical split

Top-and-bottom panels, useful for query editors, terminal splits, or
primary + detail layouts:

    <.resizable direction="vertical" class="h-[600px]">
      <.resizable_panel default_size={60} min_size={30}>
        <div class="h-full overflow-auto p-4">Top panel (query editor)</div>
      </.resizable_panel>
      <.resizable_handle />
      <.resizable_panel default_size={40} min_size={20}>
        <div class="h-full overflow-auto p-4">Bottom panel (results)</div>
      </.resizable_panel>
    </.resizable>

## Three-column layout (master-detail-info)

    <.resizable class="h-screen">
      <.resizable_panel default_size={20} min_size={15} max_size={30}>
        <%!-- Sidebar navigation --%>
        <nav class="h-full overflow-y-auto p-4">...</nav>
      </.resizable_panel>
      <.resizable_handle />
      <.resizable_panel default_size={50} min_size={30}>
        <%!-- Main content --%>
        <main class="h-full overflow-y-auto p-4">...</main>
      </.resizable_panel>
      <.resizable_handle />
      <.resizable_panel default_size={30} min_size={20} max_size={40}>
        <%!-- Detail/properties panel --%>
        <aside class="h-full overflow-y-auto p-4">...</aside>
      </.resizable_panel>
    </.resizable>

## IDE-style layout (file tree + editor + terminal)

    <.resizable direction="vertical" class="h-screen">
      <.resizable_panel default_size={70}>
        <.resizable class="h-full">
          <.resizable_panel default_size={20} min_size={15}>
            <div class="h-full p-2">File tree</div>
          </.resizable_panel>
          <.resizable_handle />
          <.resizable_panel default_size={80}>
            <div class="h-full p-4">Editor</div>
          </.resizable_panel>
        </.resizable>
      </.resizable_panel>
      <.resizable_handle />
      <.resizable_panel default_size={30} min_size={10}>
        <div class="h-full p-2 font-mono text-sm">Terminal</div>
      </.resizable_panel>
    </.resizable>

## Panel size model

Panel sizes are percentages (0–100). The CSS `flex` property is set to
`flex: N 1 0%` where `N` is the `default_size`. The `PhiaResizable` hook
reads `data-min-size` and `data-max-size` from each panel to clamp dragging.

## Accessibility

- The `resizable_handle/1` carries `role="separator"` and `tabindex="0"`
  so keyboard users can focus it and adjust the split with arrow keys.
- `aria-valuenow`, `aria-valuemin`, and `aria-valuemax` communicate the
  current split position to assistive technologies.

# `resizable`

Renders the resizable container.

Attaches the `PhiaResizable` JavaScript hook via `phx-hook`. The hook
reads the `data-direction` attribute to determine drag axis. Requires the
`PhiaResizable` hook to be registered in your `LiveSocket` hooks.

Always set an explicit height on the container so the panels have space
to fill — the container uses `h-full w-full` internally:

    <.resizable class="h-[500px]">
      ...
    </.resizable>

## Attributes

* `direction` (`:string`) - Split direction: `"horizontal"` (panels side-by-side) or `"vertical"` (panels top-and-bottom). Defaults to `"horizontal"`. Must be one of `"horizontal"`, or `"vertical"`.
* `class` (`:string`) - Additional CSS classes applied to the container `<div>`. Always set an explicit height (e.g. `class="h-[400px]"`) so panels have space to fill. Defaults to `nil`.
* Global attributes are accepted. HTML attributes forwarded to the container `<div>` element.
## Slots

* `inner_block` (required) - Alternating `resizable_panel/1` and `resizable_handle/1` children.

# `resizable_handle`

Renders the drag handle between two resizable panels.

The handle is a thin `<div>` with a 1px `bg-border` line and an expanded
interactive hit area via an `::after` pseudo-element. It is keyboard
focusable (`tabindex="0"`) and carries ARIA separator attributes.

Place one handle between each pair of adjacent panels:

    <.resizable_panel ...>...</.resizable_panel>
    <.resizable_handle />                         <%!-- between panels --%>
    <.resizable_panel ...>...</.resizable_panel>

Keyboard interaction (managed by the `PhiaResizable` hook):
- `ArrowLeft` / `ArrowRight` — adjust horizontal split.
- `ArrowUp` / `ArrowDown` — adjust vertical split.

## Attributes

* `class` (`:string`) - Additional CSS classes applied to the handle `<div>`. Defaults to `nil`.
* Global attributes are accepted. HTML attributes forwarded to the handle `<div>` element.

# `resizable_panel`

Renders a resizable panel inside a `resizable/1` container.

The panel's initial size is set via CSS `flex: N 1 0%` where `N` is the
`default_size`. The hook stores `data-default-size`, `data-min-size`, and
`data-max-size` for runtime clamping during drag operations.

Panels use `overflow-hidden` by default to prevent content from breaking
the layout. Override with `class="overflow-auto"` when the panel content
should scroll independently.

## Example

    <.resizable_panel default_size={40} min_size={20} max_size={70}>
      <div class="h-full overflow-auto p-4">
        Panel content
      </div>
    </.resizable_panel>

## Attributes

* `default_size` (`:integer`) - Initial panel size as a percentage of the container (0–100). The sum of all panel `default_size` values should equal 100. Defaults to `50`.
* `min_size` (`:integer`) - Minimum panel size as a percentage. The hook clamps dragging so this panel cannot shrink below this value. Defaults to `10`.
* `max_size` (`:integer`) - Maximum panel size as a percentage. The hook clamps dragging so this panel cannot grow beyond this value. Defaults to `90`.
* `class` (`:string`) - Additional CSS classes applied to the panel `<div>`. Typically `overflow-auto` or `overflow-hidden`. Defaults to `nil`.
* Global attributes are accepted. HTML attributes forwarded to the panel `<div>` element.
## Slots

* `inner_block` (required) - Panel content.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
