Layout
Layout sets the breakpoints, the fixed measures of the app shell, and the width of each page and overlay.
Breakpoints
The breakpoints are Tailwind v4’s. A breakpoint is a minimum viewport width.
| Breakpoint | Minimum Width | Change in a Component |
|---|---|---|
sm | 640px | A Dialog, an Alert Dialog, and a side Sheet or Drawer change to their fixed widths. A Dialog’s footer becomes a row. |
md | 768px | The Sidebar docks next to the page. The text of an Input, a Textarea, and a Native Select changes from 16px to 14px. |
lg | 1024px | None |
xl | 1280px | None |
2xl | 1536px | None |
See Typography for the rule on the 16px text of a field below md.
Shell Measures
The app shell is a Sidebar, a header, and the page. SidebarProvider sets the Sidebar’s two widths as variables.
| Part | Size | Source |
|---|---|---|
| Sidebar | 256px wide | --sidebar-width, 16rem |
| Sidebar collapsed to its icons | 48px wide | --sidebar-width-icon, 3rem |
| Sidebar below 768px | 75% of the screen, and at most 384px from 640px | The Sheet it opens in |
| Header | 48px tall | h-12 on the header inside SidebarInset |
Overlay Widths
An overlay has a fixed width from 640px. A Sheet or a Drawer on the top or the bottom edge spans the screen.
| Overlay | Width |
|---|---|
| Dialog | 576px from 640px. Below that, the screen less 16px on each side. |
| Alert Dialog | 384px from 640px. 320px below that, and at size="sm". |
| Sheet or Drawer on the left or the right | 384px from 640px. Below that, 75% of the screen. |
| Popover | 288px |
| Hover Card | 256px |
| Tooltip | At most 320px |
| A toast from Sonner | 356px from 640px. At 600px or less, the screen less 16px on each side. |
| Toast | 384px, or the screen less 16px on each side if that is narrower |
Page Widths
A page has one of three widths, depending on its content. In the figure, each frame is a 1440px screen at one tenth of its size.
| Page | Class | Width | Purpose |
|---|---|---|---|
| Data | None | The full width | A Table or a dashboard |
| Default | max-w-7xl | 1280px | All other pages, and the marketing site |
| Form or reading | max-w-2xl | 672px | A form or a long text |
Rules
The Sidebar already follows the first rule. Apply the other two to a page built inside the shell.
Shell Breakpoint
The shell has one viewport breakpoint. Below 768px, the Sidebar is removed from the page and opens in a Sheet. From 768px, it is docked next to the page. Avoid switching the shell at another width: useMobile and the Sidebar’s md: classes both use 768px, and a second width creates a range where one reports a phone and the other a desktop.
Container Queries
Inside the shell, make a component respond to the width of its container. A Field with orientation="responsive" does: it places its label next to its control when its field group is at least 448px wide. On one screen, the same form then has one layout in a 576px Dialog and another in a 384px Sheet.
Card Grids
Summit has no column grid. Use equal tracks with grid-cols-* and one gap-4, and change the number of tracks at a breakpoint. For example, grid gap-4 sm:grid-cols-2 xl:grid-cols-4 places one Card in a row below 640px, two from 640px, and four from 1280px.
Accessibility
A page must work at a width of 320 CSS pixels without scrolling in two directions, the floor of WCAG 2.2 SC 1.4.10 Reflow. That width is a 1280px window at 400% zoom. Three mechanisms address this.
- A class with no prefix is the layout at 320px because every breakpoint is a minimum width.
- An overlay stays inside the screen. On a 320px screen, a Dialog is 288px wide.
- A Table wraps itself in a container that scrolls sideways, so wide columns scroll inside it and the page around it reflows. The criterion exempts a data table.
No component reads the screen’s orientation, so a layout depends on width alone. This addresses WCAG 2.2 SC 1.3.4 Orientation.
In Code
To apply a class from a viewport width, prefix it with a breakpoint. To apply it from a container’s width, mark the container with @container and prefix the class with @, as in @md:flex-row.
<div className="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
<Card />
<Card />
<Card />
<Card />
</div>useMobile
useMobile reports whether the viewport is narrower than 768px. It is the shell’s breakpoint in script, and the Sidebar reads it to open in a Sheet.
falsenpx shadcn@latest add @summit/use-mobileThe CLI also adds the hook when you add @summit/sidebar.
import { useMobile } from '@/hooks/use-mobile';
function Filters() {
const mobile = useMobile();
return mobile ? <FiltersDrawer /> : <FiltersPopover />;
}The hook has no arguments, and its width is fixed. It listens to a media query, so a component renders again when the viewport crosses 768px, not on every resize. On the server, it returns false, so the first render on a phone is the desktop branch. Hide that branch below md with a class, as the Sidebar does with hidden md:block.
Use a class when a class can do the work. md:hidden is already correct in the server’s HTML, and the hook is correct only after the page’s scripts run. Use the hook when the markup itself differs, as the Sidebar’s does.