Skip to content

shadcn.io is an independent project built on shadcn/ui

Free

With Resizable Panels Scroll Area for Svelte

Two panels side by side, Files and Preview, with a drag handle between them. Each panel scrolls on its own.

UI library: Ark UI

Files and Preview sit side by side, with a drag handle between them. Files lists file-1.tsx onward. Preview is titled File Content and holds several paragraphs. Each side scrolls.

Use two scrolling panes for a list and a preview, such as a file browser. A Resizable pair is enough when each side is short. Ark UI in Svelte does not read the files.

Preview

Preview width

Installation

MCP · Pro
Make your AI a shadcn expert
Your agent installs components, builds pages and restyles your app from one prompt, in Claude Code, Cursor or VS Code.
Part of Pro

Anatomy

Scroll Area anatomy: root, viewport, content, scrollbar, thumb

Usage

<Resizable class="max-w-4xl rounded-lg border bg-background" defaultSize={[50, 50]} panels={[
      { id: "files", minSize: 30 },
      { id: "preview", minSize: 30 },
    ]}><ResizablePanel id="files"><div class="flex h-[400px] flex-col"><div class="border-b p-4"><h3 class="font-semibold">Files</h3></div><ScrollArea class="min-h-0 flex-1"><div class="flex flex-col gap-1 p-2">{#each files as file (file.name)}<button class="w-full rounded-md px-3 py-2 text-start text-sm transition-colors hover:bg-accent" type="button"><div class="font-medium">{file.name}</div><div class="text-muted-foreground text-xs">{file.updated}</div></button>{/each}</div></ScrollArea></div></ResizablePanel><ResizableResizeTrigger id="files:preview" withHandle /><ResizablePanel id="preview"><div class="flex h-[400px] flex-col"><div class="border-b p-4"><h3 class="font-semibold">Preview</h3></div><ScrollArea class="min-h-0 flex-1"><div class="flex flex-col gap-4 p-4"><div><h4 class="mb-2 font-medium text-sm">File Content</h4><p class="text-muted-foreground text-sm">Select a file from the list to view its contents here. The panel width can be adjusted by dragging the resize handle.</p></div><div class="flex flex-col gap-2">{#each paragraphs as paragraph (paragraph)}<p class="text-muted-foreground text-sm">{paragraph}</p>{/each}</div></div></ScrollArea></div></ResizablePanel></Resizable>

FAQ

How are the two panels sized?

Files and Preview sit side by side. Each one starts at half the group. defaultSize is [50, 50] on Resizable. panels lists { id: "files", minSize: 30 } and { id: "preview", minSize: 30 }, and each ResizablePanel repeats that id. The trigger id is files:preview.

What does withHandle do?

ResizableResizeTrigger sets withHandle, which shows the grip between Files and Preview. The trigger's accessible name is Resize. Focus it and the arrow keys change the sizes. Home and End jump toward the ends of the range.

Why do the scroll areas use min-h-0 and flex-1?

Each panel's body is a h-[400px] column, flex flex-col. The header is a border-b row. ScrollArea has min-h-0 flex-1, so it takes the height left under that header and scrolls inside it.

What is in the Files list?

Thirty buttons, type button, labeled file-1.tsx through file-30.tsx, each with "Updated N days ago" in text-xs text-muted-foreground. The button is w-full with px-3 py-2 and hover:bg-accent. The list wrapper is gap-1 p-2.

What is in the Preview pane?

A heading "File Content", a short paragraph, then six more paragraphs in flex flex-col gap-2. The text is text-sm text-muted-foreground, with p-4 on the wrapper. The header above the area reads Preview.

What wraps the two panels?

Resizable has className max-w-4xl rounded-lg border bg-background. Each header is p-4 with an h3. The two scroll areas are separate, so each pane scrolls on its own.

API Reference

Resizable

Sets defaultSize={[50, 50]}, panels, id, files, minSize and 30. The rest is on the Resizable page.

Scroll Area

No extra props in this demo. The rest is on the Scroll Area page.