Quaff

Adaptive layouts

Quaff uses Material Design 3 breakpoints throughout its JavaScript helpers, grid classes, and responsive Sass mixins. Resize this record catalog to see navigation and list/detail panes adapt.

0px · xs · Bottom bar · One pane. Wider previews scroll horizontally.

SIDE ROOM RECORDS

Independent sounds.

Releases

Window sizes

KeyWidthMD3 size
xs< 600pxCompact
sm600–< 840pxMedium
md840–< 1200pxExpanded
lg1200–< 1600pxLarge
xl≥ 1600pxExtra-large
import { Quaff } from "@quaffui/quaff";

Quaff.screen.name;       // "xs" | "sm" | "md" | "lg" | "xl"
Quaff.screen.gt.md;      // Above the md class: at least 1200px
!Quaff.screen.lt.md;     // md or wider: at least 840px
Quaff.screen.navigation; // "navbar" below 600px, otherwise "railbar"
Quaff.screen.twoPane;    // true from 840px

Quaff.screen provides reactive, read-only viewport dimensions and size flags. Its gt.md flag means above the entire md class, while !Quaff.screen.lt.md includes md.

Call Quaff.init() once during root layout setup, including in client-only apps. Until the root mounts, the viewport is 0 × 0, name is "xs", and ready is false. Live measurements begin on mount, keeping the initial server render and hydration consistent.

Navigation

Share destinations between a bottom bar on compact windows and a rail on larger windows. Render each in its QLayout slot.

{#snippet destinations()}
  <QNavItem icon="album" label="Catalog" href="/catalog" />
  <!-- More destinations -->
{/snippet}

<QLayout>
  {#snippet navbar()}
    {#if Quaff.screen.navigation === "navbar"}
      <QNavbar>{@render destinations()}</QNavbar>
    {/if}
  {/snippet}
  {#snippet railbarStart()}
    {#if Quaff.screen.navigation === "railbar"}
      <QRailbar>{@render destinations()}</QRailbar>
    {/if}
  {/snippet}
  <!-- Application content -->
</QLayout>

List and detail

Compact and medium windows show one pane. From 840px, the usual list/detail arrangement shows both. Keep selection and Back behavior in your app; keep panes mounted to preserve scroll and form state.

import { Quaff } from "@quaffui/quaff";

let showDetail = $state(false); // Set true on selection; false on Back.
const twoPane = $derived(Quaff.screen.twoPane);
<div class="row q-gutter-lg">
  <section class="col-xs-12 col-md-6" hidden={!twoPane && showDetail}>
    <!-- List -->
  </section>
  <section class="col-xs-12 col-md-6" hidden={!twoPane && !showDetail}>
    <!-- Selected item or empty state -->
  </section>
</div>

This demo uses 16px margins on compact windows, 24px margins and pane gaps above that, and a 360px list pane from 840px (412px from 1200px). Adapt the arrangement to your content. Show list selection only when both panes are visible, and move focus when a focused pane or navigation disappears.

Embedded layouts

For an app inside a container, derive its screen state from the measured width:

import { Quaff } from "@quaffui/quaff";

let width = $state<number>();
const screen = $derived(Quaff.getScreen(width));
<div bind:clientWidth={width}><!-- Use screen here. --></div>

getScreen returns the same ScreenState shape and accepts an optional height, defaulting to 0. It is pure and needs no Quaff.init(). Its ready flag is false until width is a valid measurement; 0 is valid, while undefined means unavailable. Grid classes and Sass media queries always follow the viewport, not this container.

See the grid utilities and MD3 breakpoint guidance.