Breakpoints and grid
Five size classes and one grid. The window decides how many columns there are; the cards are arranged once, for the desktop, and every other width is derived from that arrangement.
Size classes
The classes follow Material 3, with thresholds set by the cards: a card should never be narrower than a phone or wider than about 575 px, where a row of figures stops reading as one line. When a column would grow past that, the grid gains a column, up to five: on the widest monitors, cards reach 614 px.
| Size class | Window | Columns | Navigation | Margins | Card width |
|---|---|---|---|---|---|
compact
Phones
|
360–767 px | 1 | Bottom bar | 16 px | 328–735 px |
medium
Tablets
|
768–1279 px | 2 | Rail | 24 px | 320–575 px |
expanded
Desktops
|
1280–2047 px | 3 | Sidebar | 32 px | 317–573 px |
large
Wide monitors
|
2048–2649 px | 4 | Sidebar | 32 px | 425–575 px |
extra-large
Ultra-wide monitors
|
2650 px and wider | 5 | Sidebar | 32 px | 456–614 px |
Card widths with the sidebar open. Collapsing it to the rail gives the columns its width.
The grid at any width
- Size class
- expanded
- Columns
- 3
- Column width
- 370 px
- Margins
- 32 px
- Navigation
- Sidebar, 224 px
Column width
Columns are fluid: they share whatever the navigation and the margins leave, rounded down to whole pixels so card edges stay sharp. Collapsing the sidebar on a 1440 px desktop widens every column from 370 to 425 px; the cards follow with the same spring as the sidebar.
column = ⌊(window − navigation − 2 × margin
− (columns − 1) × gap) ÷ columns⌋
1440 px desktop, sidebar open:
⌊(1440 − 224 − 2 × 32 − 2 × 20) ÷ 3⌋ = 370 px
Card heights
Cards come in four heights. Width is the column’s; a card never spans two. The heights are chosen so that M + L = S + XL: two columns built from different sizes end level, and the overview keeps a straight bottom edge as people rearrange it.
- S 245 px
- M 375 px
- L 405 px
- XL 535 px
One layout, derived
- The desktop layout is the one people design. They choose each card’s column, position and size on a three-column desktop.
- Every other width reads it in order. Cards are taken by how far down they start, and left to right when two start level. Each goes into the shortest column. One column on phones keeps the same order, so the first card on a desktop is the first card on a phone.
- A layout edited at another width is kept for that width. Rearranging cards on a tablet stores a tablet layout; until then, the tablet follows the desktop. What is shown is shared: hiding a card hides it everywhere.
On a tablet, the six cards of the default overview land as Orders, Balance, Recurring orders and Daily shipments, Deliveries, Inventory .
In code
Media queries cannot read custom properties, so the token build writes the breakpoints into them. Three properties
follow the size class on their own:
--sonar-layout-columns
,
--sonar-layout-margin
and
--sonar-layout-bar-top
. Components read those, never a breakpoint.
/* The overview grid: columns, gap and margins follow the size class */
.overview {
display: grid;
grid-template-columns: repeat(var(--sonar-layout-columns), minmax(0, 1fr));
gap: var(--sonar-layout-gap);
padding-inline: var(--sonar-layout-margin);
}
.top-app-bar {
block-size: calc(var(--sonar-layout-bar-top) + env(safe-area-inset-top, 0px));
padding-block-start: env(safe-area-inset-top, 0px);
}
For scripts, the package exports each size class with a media query for exactly its range.
import { sizeClasses } from '@orbex/sonar-tokens'
/* The current size class, kept up to date as the window changes */
const current = () => sizeClasses.find(({ media }) => matchMedia(media).matches)!.name
Safe areas
On phones and tablets in full screen, the system draws its status bar and home indicator over the page. The app
bars grow by env(safe-area-inset-*) so their background reaches the edge, and the content starts below
them. In a browser tab the insets are zero and nothing changes.
Tokens
| Token | Value |
|---|---|
--sonar-layout-columns-compact
|
1
|
--sonar-layout-columns-medium
|
2
|
--sonar-layout-columns-expanded
|
3
|
--sonar-layout-columns-large
|
4
|
--sonar-layout-columns-extra-large
|
5
|
--sonar-layout-margin-compact
|
16px
|
--sonar-layout-margin-medium
|
24px
|
--sonar-layout-margin-expanded
|
32px
|
--sonar-layout-gap
Between cards, in every size class. |
20px
|
--sonar-layout-sidebar
Full navigation beside the content on desktops. On tablets it opens over the content. |
224px
|
--sonar-layout-rail
Navigation as icons only: the rail on tablets and the collapsed sidebar on desktops. |
60px
|
--sonar-layout-drawer
The sidebar as a drawer on phones. It never covers more than 84% of the window. |
304px
|
--sonar-layout-bar-top-compact
|
56px
|
--sonar-layout-bar-top-medium
|
68px
|
--sonar-layout-bar-bottom
Bottom app bar on phones: Alerts, Assistant, Edit, Account and Menu. |
60px
|
--sonar-layout-bar-footer
Footer and edit bar on tablets and desktops. |
46px
|
--sonar-layout-card-s
|
245px
|
--sonar-layout-card-m
|
375px
|
--sonar-layout-card-l
|
405px
|
--sonar-layout-card-xl
|
535px
|
--sonar-layout-touch-target
Minimum hit area on touch screens. |
48px
|