Siteplane UI

Frame

Group raised panels inside a shared frame.

Markdown
Plan
Your subscription and renewal date.

Pro plan

$20 per month, renews on October 1, 2026.
"use client";

import {
  Frame,
  FrameDescription,
  FrameFooter,
  FrameHeader,
  FramePanel,
  FrameTitle,
} from "@/siteplane/components/frame";

export default function Example() {
  return (
    <Frame className="w-full max-w-md">
      <FrameHeader>
        <FrameTitle>Plan</FrameTitle>
        <FrameDescription>Your subscription and renewal date.</FrameDescription>
      </FrameHeader>
      <FramePanel>
        <FrameTitle>
          <h3>Pro plan</h3>
        </FrameTitle>
        <FrameDescription>
          $20 per month, renews on October 1, 2026.
        </FrameDescription>
      </FramePanel>
      <FrameFooter>
        <FrameDescription>
          Plan changes take effect on your next billing date.
        </FrameDescription>
      </FrameFooter>
    </Frame>
  );
}

Installation

pnpm dlx shadcn@4.18.0 add @siteplane/frame

Complete the one-time setup first. Registry JSON lists source files and dependencies.

For this page’s examples, also install:

pnpm dlx shadcn@4.18.0 add @siteplane/separator

Usage

import { Frame, FramePanel } from "@/siteplane/components/frame";

<Frame>
  <FramePanel>Content</FramePanel>
</Frame>;

Composition

Frame
├── FrameHeader
│   ├── FrameTitle
│   └── FrameDescription
├── FramePanel
└── FrameFooter

Separated panels

Place several FramePanel parts directly inside Frame; adjacent panels are spaced apart automatically.

Workspace usage
Current billing period.

Members

12 of 20 seats in use.

Storage

4.2 GB of 10 GB used.
"use client";

import {
  Frame,
  FrameDescription,
  FrameHeader,
  FramePanel,
  FrameTitle,
} from "@/siteplane/components/frame";

export default function Example() {
  return (
    <Frame className="w-full max-w-md">
      <FrameHeader>
        <FrameTitle>Workspace usage</FrameTitle>
        <FrameDescription>Current billing period.</FrameDescription>
      </FrameHeader>
      <FramePanel>
        <FrameTitle>
          <h3>Members</h3>
        </FrameTitle>
        <FrameDescription>12 of 20 seats in use.</FrameDescription>
      </FramePanel>
      <FramePanel>
        <FrameTitle>
          <h3>Storage</h3>
        </FrameTitle>
        <FrameDescription>4.2 GB of 10 GB used.</FrameDescription>
      </FramePanel>
    </Frame>
  );
}

Stacked sections

To stack sections inside one panel, remove the panel padding and divide the sections with a Separator.

Payment details
Used for your monthly invoices.

Payment method

Card ending in 4242, expires 08/2028.

Billing contact

Invoices are sent to billing@example.com.
"use client";

import {
  Frame,
  FrameDescription,
  FrameHeader,
  FramePanel,
  FrameTitle,
} from "@/siteplane/components/frame";
import { Separator } from "@/siteplane/components/separator";

export default function Example() {
  return (
    <Frame className="w-full max-w-md">
      <FrameHeader>
        <FrameTitle>Payment details</FrameTitle>
        <FrameDescription>Used for your monthly invoices.</FrameDescription>
      </FrameHeader>
      <FramePanel className="p-0">
        <div className="p-5">
          <FrameTitle>
            <h3>Payment method</h3>
          </FrameTitle>
          <FrameDescription>
            Card ending in 4242, expires 08/2028.
          </FrameDescription>
        </div>
        <Separator />
        <div className="p-5">
          <FrameTitle>
            <h3>Billing contact</h3>
          </FrameTitle>
          <FrameDescription>
            Invoices are sent to billing@example.com.
          </FrameDescription>
        </div>
      </FramePanel>
    </Frame>
  );
}

API reference

All parts accept native attributes, refs, children and string className. Frame is a div with a muted background, rounded corners and padding; FramePanel is a padded card surface with the same edge as Card; FrameHeader, FrameTitle, FrameDescription and FrameFooter render div, so a page with many frames adds no landmarks. There are no owned size, variant or state props. Use native headings within the title where needed; FrameTitle does not create one.

Read the installed source.

Usage notes

Frame owns presentation only. Use Card for a card with its own header, content and actions, or CardFrame for cards joined within a surrounding surface.

A panel is lighter than the muted frame around it. It draws the same hairline as a Card and adds no border or shadow of its own.