HextaUI

Resizable

Birbirinden ayırabileceğiniz paneller; hover'da uyanan sakin bir ayırıcı, sıfırlama ya da daraltmada kayarak değişen boyutlar ve kalıcı düzenler sunar.

ExplorerDrag the divider, or double-click it to reset.
EditorFocus a divider and use the arrow keys.
Terminal
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable"

function Pane({ title, children }: { title: string; children?: string }) {
  return (
    <div className="flex h-full flex-col gap-1 p-4">
      <span className="text-sm font-medium">{title}</span>
      <span className="text-sm text-muted-foreground">{children}</span>
    </div>
  )
}

export function ResizableDemo() {
  return (
    <div className="h-80 w-full max-w-2xl overflow-hidden rounded-xl border">
      <ResizablePanelGroup>
        <ResizablePanel defaultSize="28%" minSize="18%" maxSize="45%">
          <Pane title="Explorer">
            Drag the divider, or double-click it to reset.
          </Pane>
        </ResizablePanel>
        <ResizableHandle />
        <ResizablePanel>
          <ResizablePanelGroup orientation="vertical">
            <ResizablePanel defaultSize="65%" minSize="25%">
              <Pane title="Editor">
                Focus a divider and use the arrow keys.
              </Pane>
            </ResizablePanel>
            <ResizableHandle />
            <ResizablePanel minSize="15%">
              <Pane title="Terminal" />
            </ResizablePanel>
          </ResizablePanelGroup>
        </ResizablePanel>
      </ResizablePanelGroup>
    </div>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/resizable.json

Bileşeni, HextaUI tema token'larını ve bileşenin bağımlı olduğu tüm HextaUI bileşenlerini ekler.

import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable"
<ResizablePanelGroup>
  <ResizablePanel defaultSize="30%" minSize="20%">Sidebar</ResizablePanel>
  <ResizableHandle />
  <ResizablePanel>Content</ResizablePanel>
</ResizablePanelGroup>

Sayılar piksel, dizeler yüzdedir; dolayısıyla defaultSize="30%" ve minSize={240} ikisi de çalışır. Ayırıcı siz ona uzanana kadar ince bir çizgi kalır. Sürüklerken paneller imleci tam olarak izler; çift tıklamayla sıfırlama, klavye adımları ve koddan daraltma dahil diğer her değişiklik süzülerek gerçekleşir.

ResizablePanelGroup
├── ResizablePanel
├── ResizableHandle
└── ResizablePanel

Collapsible

collapsible bir panel, minSize değerinin altına sürüklendiğinde kapanır. Onu usePanelRef ile bir düğmeden açıp kapatın; daralma animasyonludur.

"use client"

import * as React from "react"
import { IconLayoutSidebar } from "@tabler/icons-react"

import { Button } from "@/components/ui/button"
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
  usePanelRef,
} from "@/components/ui/resizable"

export function ResizableCollapsible() {
  const sidebar = usePanelRef()
  const [collapsed, setCollapsed] = React.useState(false)

  return (
    <div className="flex h-72 w-full max-w-2xl flex-col overflow-hidden rounded-xl border">
      <div className="flex items-center gap-2 border-b p-2">
        <Button
          variant="ghost"
          size="icon-sm"
          aria-label={collapsed ? "Show sidebar" : "Hide sidebar"}
          aria-pressed={!collapsed}
          onClick={() => {
            if (sidebar.current?.isCollapsed()) {
              sidebar.current.expand()
            } else {
              sidebar.current?.collapse()
            }
          }}
        >
          <IconLayoutSidebar />
        </Button>
        <span className="text-sm text-muted-foreground">
          Drag the sidebar narrow to collapse it, or press Enter on the divider.
        </span>
      </div>
      <div className="min-h-0 flex-1">
        <ResizablePanelGroup>
          <ResizablePanel
            panelRef={sidebar}
            collapsible
            defaultSize="30%"
            minSize="20%"
            collapsedSize="0%"
            onResize={(size) => setCollapsed(size.asPercentage === 0)}
          >
            <div className="flex h-full flex-col gap-1 p-4 text-sm">
              <span className="font-medium">Inbox</span>
              <span className="text-muted-foreground">Drafts</span>
              <span className="text-muted-foreground">Archive</span>
            </div>
          </ResizablePanel>
          <ResizableHandle />
          <ResizablePanel minSize="40%">
            <div className="flex h-full items-center justify-center text-sm font-medium">
              Message
            </div>
          </ResizablePanel>
        </ResizablePanelGroup>
      </div>
    </div>
  )
}

Boyut göstergesi

showSize, sürüklerken veya klavye kullanırken ayırıcıdan önceki paneli "percent" veya "pixels" cinsinden gösterir.

import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable"

export function ResizableSize() {
  return (
    <div className="h-56 w-full max-w-xl overflow-hidden rounded-xl border">
      <ResizablePanelGroup>
        <ResizablePanel defaultSize="320px" minSize="160px" maxSize="70%">
          <div className="flex h-full items-center justify-center text-sm font-medium">
            Canvas
          </div>
        </ResizablePanel>
        <ResizableHandle showSize="pixels" />
        <ResizablePanel minSize="20%">
          <div className="flex h-full items-center justify-center text-sm font-medium">
            Inspector
          </div>
        </ResizablePanel>
      </ResizablePanelGroup>
    </div>
  )
}

Yerleşimi hatırla

useDefaultLayout boyutları localStorage'a kaydeder ve bir sonraki ziyarette animasyonsuz geri yükler. Her panele bir id verin.

"use client"

import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
  useDefaultLayout,
} from "@/components/ui/resizable"

export function ResizablePersist() {
  const { defaultLayout, onLayoutChanged } = useDefaultLayout({
    id: "hextaui-resizable-persist",
  })

  return (
    <div className="h-56 w-full max-w-md overflow-hidden rounded-xl border">
      <ResizablePanelGroup
        defaultLayout={defaultLayout}
        onLayoutChanged={onLayoutChanged}
      >
        <ResizablePanel id="list" defaultSize="40%" minSize="20%">
          <div className="flex h-full items-center justify-center p-4 text-center text-sm font-medium">
            Resize me, then reload
          </div>
        </ResizablePanel>
        <ResizableHandle />
        <ResizablePanel id="detail" minSize="20%">
          <div className="flex h-full items-center justify-center text-sm font-medium">
            Detail
          </div>
        </ResizablePanel>
      </ResizablePanelGroup>
    </div>
  )
}

Dikey

orientation="vertical" panelleri üst üste dizer. Gruplar, yukarıdaki demoda olduğu gibi iç içe geçebilir.

import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable"

export function ResizableVertical() {
  return (
    <div className="h-72 w-full max-w-md overflow-hidden rounded-xl border">
      <ResizablePanelGroup orientation="vertical">
        <ResizablePanel defaultSize="30%" minSize="20%">
          <div className="flex h-full items-center justify-center text-sm font-medium">
            Header
          </div>
        </ResizablePanel>
        <ResizableHandle />
        <ResizablePanel minSize="30%">
          <div className="flex h-full items-center justify-center text-sm font-medium">
            Content
          </div>
        </ResizablePanel>
      </ResizablePanelGroup>
    </div>
  )
}

Görünür tutamaç

withHandle, tutamacı hover'da ortaya çıkarmak yerine sürekli gösterir.

import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable"

export function ResizableWithHandle() {
  return (
    <div className="h-56 w-full max-w-md overflow-hidden rounded-xl border">
      <ResizablePanelGroup>
        <ResizablePanel defaultSize="40%" minSize="20%">
          <div className="flex h-full items-center justify-center text-sm font-medium">
            Preview
          </div>
        </ResizablePanel>
        <ResizableHandle withHandle />
        <ResizablePanel minSize="20%">
          <div className="flex h-full items-center justify-center text-sm font-medium">
            Code
          </div>
        </ResizablePanel>
      </ResizablePanelGroup>
    </div>
  )
}

Sağdan sola

Paneller ve ok tuşları okuma yönünü izler.

import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable"

export function ResizableRtl() {
  return (
    <div
      dir="rtl"
      className="h-56 w-full max-w-md overflow-hidden rounded-xl border"
    >
      <ResizablePanelGroup>
        <ResizablePanel defaultSize="35%" minSize="20%">
          <div className="flex h-full items-center justify-center text-sm font-medium">
            القائمة
          </div>
        </ResizablePanel>
        <ResizableHandle showSize />
        <ResizablePanel minSize="20%">
          <div className="flex h-full items-center justify-center text-sm font-medium">
            المحتوى
          </div>
        </ResizablePanel>
      </ResizablePanelGroup>
    </div>
  )
}
TuşAction
←→↑↓Odaktaki ayırıcıyı grubunun yönü boyunca %5 hareket ettirir.
HomeEndAyırıcıyı panellerin izin verdiği kadar hareket ettirir.
EnterDaraltılabilir bir paneli daraltır veya genişletir.
F6Gruptaki sonraki ayırıcıya geçer; Shift geri götürür.
  • Her ayırıcı, kendinden önceki panelin boyutunu bildiren, odaklanabilir bir separator'dır.
  • Boyut göstergesi dekoratiftir; ekran okuyucular separator'ın kendi değerini alır.
  • Azaltılmış harekette boyutlar anında değişir ve ayırıcı animasyonlanmaz.
PropTürVarsayılan
orientation
"horizontal" | "vertical""horizontal"
defaultLayout
Layout–
onLayoutChangeSürükleme sırası dahil her değişiklik.
(layout) => void–
onLayoutChangedBir değişiklik oturduğunda.
(layout, meta) => void–
disabled
booleanfalse
groupRef
Ref<GroupImperativeHandle>–
ÖznitelikAçıklama
data-slot="resizable-panel-group"Grup.
data-readyMount sonrasında ayarlanır; boyutlar o andan itibaren animasyonlanır.
PropTürVarsayılan
defaultSize
number | string–
minSize
number | string–
maxSize
number | string–
collapsible
booleanfalse
collapsedSize
number | string0
onResize
(size, id, previous) => void–
panelRef
Ref<PanelImperativeHandle>–
idYerleşimleri hatırlamak için gerekir.
string–
PropTürVarsayılan
withHandleTutamacı her zaman göster.
booleanfalse
showSize
boolean | "percent" | "pixels"false
disableDoubleClickÇift tıklamanın panelleri sıfırlamasını engeller.
booleanfalse
disabled
booleanfalse
ÖznitelikAçıklama
data-slot="resizable-handle"Ayırıcı.
data-separator"inactive", "hover", "active", "focus" veya "disabled".
data-slot="resizable-handle-grip"Tutamaç hapı.

usePanelRef ve useGroupRef size collapse, expand, resize ve setLayout verir. useDefaultLayout bir grubun yerleşimini kalıcı kılar.

Kullanıldığı bloklar

Resizable üzerine kurulan bloklar.