- Accordion
- AppShell
- Autocomplete
- Badge
- Blobatar
- BoringAvatar
- Button
- Calendar
- Checkbox
- DataGrid
- Date Picker
- Date Range Picker
- DateTime
- Dialog
- Drawer
- Dropdown
- Empty
- Error State
- Frame
- Input
- Input Amount
- Input Group
- Input OTP
- Input Password
- Input Phone
- Input Search
- Input Secret
- Loading
- PageContainer
- PageHeader
- Popover
- Select
- StatsCard
- Switch
- Tabs
- TextArea
- Toast
- Tooltip
Playground
import { PageContainer } from "@/components/ui/page-container";
export const PageContainerDemo = () => (
<PageContainer>
<div className="bg-muted py-8 text-sm text-foreground">
{"Page content"}
</div>
</PageContainer>
);Installation
Initialize shadcn in your React project, then install this component from the Vandor UI registry:
$ pnpm dlx shadcn@latest add https://vandor-ui.vercel.app/r/page-container.json
Dependencies
Installed automatically by the registry CLI. For manual setup:
- cn
$ pnpm add cnUsage
import { PageContainer } from "@/components/ui/page-container";
<main>
<PageContainer>
<h1>Workspace</h1>
</PageContainer>
</main>;PageContainer controls the width of page content and applies responsive padding: 16px below sm, 24px from sm, and 48px from lg. It is not an app shell or Card: it adds no background, border, shadow, header, sidebar, height, or scrolling behavior.
Examples
Default page
Workspace
Centered content with responsive page gutters.
import { PageContainer } from "@/components/ui/page-container";
export const PageContainerDemo = () => (
<PageContainer>
<div className="flex flex-col gap-2">
<h3 className="text-base font-medium">Workspace</h3>
<p className="text-sm text-muted-foreground">
Centered content with responsive page gutters.
</p>
</div>
</PageContainer>
);The default lg caps the outer width at 72rem. Use sm (42rem) for focused content, md (56rem) for settings, or xl (80rem) for wider pages. These are fixed maximum widths, not viewport breakpoints, and include the horizontal gutters under Tailwind's border-box reset. Sizes larger than a preview's available width can look identical.
Full-width content
Projects
| Project | Status |
|---|---|
| Website | Active |
import { PageContainer } from "@/components/ui/page-container";
export const PageContainerFullDemo = () => (
<PageContainer size="full">
<div className="flex flex-col gap-3">
<h3 className="text-base font-medium">Projects</h3>
<div className="min-w-0 overflow-x-auto">
<table className="w-full text-left text-sm">
<caption className="sr-only">Project status</caption>
<thead>
<tr className="border-b">
<th scope="col" className="p-2">
Project
</th>
<th scope="col" className="p-2">
Status
</th>
</tr>
</thead>
<tbody>
<tr>
<td className="p-2">Website</td>
<td className="p-2">Active</td>
</tr>
</tbody>
</table>
</div>
</div>
</PageContainer>
);size="full" removes the width cap but keeps the padding. Use it for dashboards and wide tables, or when content should sit equally far from the sidebar and header. With capped sizes, horizontal centering can add extra space on the left and right even though the padding is equal. The example owns its table's horizontal scrolling; PageContainer never clips content or installs an overflow policy.
Padding and overrides
Padding on every side is 1rem below 640px, 1.5rem from 640px, and 2rem from 1024px with Tailwind's default spacing and breakpoints (p-4 sm:p-6 lg:p-8). It follows your Tailwind configuration. Avoid adding page padding on a parent unless you want that extra inset.
To remove all padding at every breakpoint, use className="p-0 sm:p-0 lg:p-0". To remove only vertical padding, use className="py-0 sm:py-0 lg:py-0"; horizontal-only overrides work the same way with px-*. A base class alone does not override responsive classes. className="max-w-5xl" overrides the selected width cap. Existing pages that supplied their own vertical spacing may need those classes removed or adjusted.
Consumer setup and optional stories
Requires React 19, Tailwind CSS 4 with its preflight reset, and cn. PageContainer has no provider, animation, theme-token dependency, or client directive and can be imported by a Next.js Server Component. Example content and stories use your muted and foreground semantic tokens; these surfaces are not built into the component.
Installation uses the UI alias in your components.json. For manual setup, install cn and copy the generated Source into your UI directory. Review the CLI overwrite prompt before replacing an existing PageContainer. Playground and example files are not distributed.
Install PageContainer first, then optionally install its portable stories:
$ pnpm dlx shadcn@latest add https://vandor-ui.vercel.app/r/page-container-stories.json
Use your existing @storybook/react installation with matching Storybook package versions (types and composition checked with 10.6.1). Discover **/*.stories.tsx in your UI directory and load your global Tailwind/theme stylesheet in the preview. No extra addons or providers are required. The stories-only item does not reinstall the component or change Storybook configuration. This project has no Storybook server; Storybook UI appearance is not verified here.
Behavior & Accessibility
PageContainer renders a native div and forwards its attributes, event handlers, children, and React 19 ref. It adds no landmark, heading, focus management, state, or motion. Wrap it in your page's main rather than creating multiple main landmarks. Use native headings appropriate to your page hierarchy. Arbitrary long URLs and tables need an application-level wrapping or scrolling policy.
The playground content and size controls share configuration with the generated runnable code. Reset restores both to their defaults; the sample muted area only makes the surrounding padding visible.
Props
| Prop | Type / Description | Default |
|---|---|---|
| children | ReactNodePage content. The playground uses text inside a sample content area. | Not set |
| className | stringMerged layout classes. Override padding at each breakpoint when needed, such as p-0 sm:p-0 lg:p-0. | Not set |
| ref | Ref<HTMLDivElement>React 19 ref forwarded to the native div. | Not set |
| size | "sm" | "md" | "lg" | "xl" | "full"Maximum outer width: sm 42rem, md 56rem, lg 72rem, xl 80rem; full has no cap. Gutters are included in this width. | "lg" |
The reference lists component-specific props and selected native props, not the complete React API. Other native attributes are forwarded to the rendered element.
Source
import { cn } from "cn";
import type { ComponentProps } from "react";
const widths = {
full: "max-w-none",
lg: "max-w-6xl",
md: "max-w-4xl",
sm: "max-w-2xl",
xl: "max-w-7xl",
} as const;
export type PageContainerProps = ComponentProps<"div"> & {
size?: keyof typeof widths;
};
export const PageContainer = ({
className,
size = "lg",
...props
}: PageContainerProps) => (
<div
data-slot="page-container"
data-size={size}
className={cn(
"mx-auto w-full min-w-0 p-4 sm:p-6 lg:p-12",
widths[size],
className
)}
{...props}
/>
);