Bỏ qua đến nội dung

Có thể đổi kích thước

Các khung chia đôi có thể kéo thả dành cho trình soạn thảo mã nguồn, cây thư mục và bố cục bảng điều khiển — với phong cách viền và bóng theo trường phái tân thô mộc.

import {
  ResizableHandle,
  ResizablePanel,

Thành phần resizable chia một vùng thành các panel mà người dùng có thể kéo để thay đổi tỷ lệ — theo chiều ngang hoặc dọc, lồng nhau được, với tay kéo điều khiển được bằng bàn phím. Cả hai biến thể đều bọc thư viện react-resizable-panels của bvaughn, tạo kiểu theo công thức neobrutalist: viền dày, bóng đổ đậm và kiểu chữ đậm.

Nên dùng khi:

  • Trình soạn mã và bố cục kiểu IDE — các khung cây tệp, trình soạn thảo và xem trước để người dùng tự chỉnh kích thước theo ý.
  • Giao diện master–detail — hộp thư và luồng hội thoại, bảng dữ liệu và khung xem chi tiết bản ghi, với vạch chia đặt đúng chỗ người dùng muốn.
  • Bảng điều khiển và console — cho phép khung log hoặc terminal lấy bớt chiều cao của khung chính mà không cần modal.

Giới thiệu

Component Resizable được xây dựng dựa trên react-resizable-panels của bvaughn.

Cài đặt

pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/resizable.json
npx shadcn@latest add https://neobrutalism.com/r/base/resizable.json
yarn dlx shadcn@latest add https://neobrutalism.com/r/base/resizable.json
bunx --bun shadcn@latest add https://neobrutalism.com/r/base/resizable.json

Cài đặt các phụ thuộc sau:

pnpm add react-resizable-panels
npm install react-resizable-panels
yarn add react-resizable-panels
bun add react-resizable-panels

Sao chép và dán đoạn mã sau vào dự án của bạn.

components/ui/resizable.tsx
"use client"

import * as ResizablePrimitive from "react-resizable-panels"

import { cn } from "@/lib/utils"

function ResizablePanelGroup({
  className,
  ...props
}: ResizablePrimitive.GroupProps) {
  return (
    <ResizablePrimitive.Group
      data-slot="resizable-panel-group"
      className={cn(
        "flex h-full w-full aria-[orientation=vertical]:flex-col",
        className
      )}
      {...props}
    />
  )
}

function ResizablePanel({ ...props }: ResizablePrimitive.PanelProps) {
  return <ResizablePrimitive.Panel data-slot="resizable-panel" {...props} />
}

function ResizableHandle({
  withHandle,
  className,
  ...props
}: ResizablePrimitive.SeparatorProps & {
  withHandle?: boolean
}) {
  return (
    <ResizablePrimitive.Separator
      data-slot="resizable-handle"
      className={cn(
        "relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary aria-[orientation=horizontal]:h-px aria-[orientation=horizontal]:w-full aria-[orientation=horizontal]:after:left-0 aria-[orientation=horizontal]:after:h-1 aria-[orientation=horizontal]:after:w-full aria-[orientation=horizontal]:after:translate-x-0 aria-[orientation=horizontal]:after:-translate-y-1/2 [&[aria-orientation=horizontal]>div]:rotate-90",
        className
      )}
      {...props}
    >
      {withHandle && (
        <div className="z-10 flex h-6 w-1 shrink-0 rounded-lg bg-border" />
      )}
    </ResizablePrimitive.Separator>
  )
}

export { ResizableHandle, ResizablePanel, ResizablePanelGroup }

Cập nhật các đường dẫn import cho phù hợp với thiết lập dự án của bạn.

Cách dùng

import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable"
<ResizablePanelGroup orientation="horizontal">
  <ResizablePanel>One</ResizablePanel>
  <ResizableHandle />
  <ResizablePanel>Two</ResizablePanel>
</ResizablePanelGroup>

Kết hợp

Dùng cách kết hợp sau để xây dựng một ResizablePanelGroup:

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

Ví dụ

Dọc

Dùng orientation="vertical" để thay đổi kích thước theo chiều dọc.

import {
  ResizableHandle,
  ResizablePanel,

Tay cầm

Dùng prop withHandle trên ResizableHandle để hiển thị một tay cầm nhìn thấy được.

import {
  ResizableHandle,
  ResizablePanel,

RTL

Để bật hỗ trợ RTL trong Neobrutalism, hãy xem hướng dẫn cấu hình RTL.

"use client"

import * as React from "react"

Khả năng truy cập

Tay kéo tuân theo mẫu Window Splitter của WAI-ARIA: react-resizable-panels render mỗi tay kéo thành một phần tử role="separator" có thể focus, kèm aria-valuenow / aria-valuemin / aria-valuemaxaria-controls trỏ đến panel mà nó thay đổi kích thước, nhờ đó trình đọc màn hình đọc lên vị trí vạch chia mỗi khi thay đổi.

Tương tác bàn phím:

PhímHành động
Tab / Shift + TabDi chuyển focus vào / ra khỏi tay kéo
ArrowLeft / ArrowRightThay đổi kích thước nhóm ngang theo từng bước
ArrowUp / ArrowDownThay đổi kích thước nhóm dọc theo từng bước
HomeThu panel đứng trước tay kéo về kích thước tối thiểu
EndMở rộng panel đứng trước tay kéo đến kích thước tối đa
EnterChuyển panel có thể thu gọn giữa trạng thái thu gọn và mở rộng

Tham chiếu API

Xem tài liệu react-resizable-panels.

Nhật ký thay đổi

2025-02-02 react-resizable-panels v4

Đã cập nhật lên react-resizable-panels v4. Xem ghi chú phát hành v4.0.0 để biết đầy đủ chi tiết.

Nếu bạn dùng trực tiếp các primitive của react-resizable-panels, hãy lưu ý các thay đổi sau:

v3v4
PanelGroupGroup
PanelResizeHandleSeparator
direction proporientation prop
defaultSize={50}defaultSize="50%"
onLayoutonLayoutChange
ImperativePanelHandlePanelImperativeHandle
ref prop on PanelpanelRef prop
data-panel-group-directionaria-orientation