Critical CSS View

A page-shaped visualiser of the critical CSS optimisation. Pass in a flat list of layout zones tagged with fold: "above" | "below"; the view stacks them as a mini mock page split by a fold line, with a coverage overlay that totals inline vs deferred bytes and an action button that flips between the un-optimised state (everything dim) and the extracted state (above-the-fold crisp, below-the-fold muted).

Pair with CriticalCssWidget (which is the rules-list view) — CriticalCssView is the page-shape view of the same optimisation.

Preview

Critical CSS extractor

Above-the-fold zones land in the inline tier; the rest stream behind.

nav
hero
hero img
card grid
footer
Coverage22% inline · 78% deferred
inline 13.0 KBdeferred 44.9 KB
Customize
Zone sizes (KB)
4.7KB
5.3KB
27.3KB
17.6KB
Layout

Installation

npx shadcn@latest add https://craftbits.dev/r/critical-css-view.json

Usage

import { useState } from "react";
import { CriticalCssView, type CriticalCssViewZone } from "@craft-bits/core";
 
const zones: CriticalCssViewZone[] = [
  { id: "nav", label: "nav", fold: "above", kind: "nav", bytes: 4_800 },
  { id: "hero", label: "hero", fold: "above", kind: "hero", bytes: 5_400 },
  { id: "cards", label: "card grid", fold: "below", kind: "grid", bytes: 28_000 },
  { id: "footer", label: "footer", fold: "below", kind: "footer", bytes: 18_000 },
];
 
export function Demo() {
  const [extracted, setExtracted] = useState(false);
  return (
    <CriticalCssView
      title="Critical CSS extractor"
      zones={zones}
      extracted={extracted}
      onToggle={() => setExtracted((p) => !p)}
    />
  );
}

Omit onToggle to render the view as a presentational diagram — the consumer drives the extracted flag from a step counter or playback timeline.

Anatomy

  • Header. Optional title (rendered with the cb-label style) and description. Omit both for a chromeless panel.
  • Page mock. A stack of zone rows clipped by a dashed fold divider. Each row paints a tiny illustration matched to kind — pill row for nav, two-line block for hero, image placeholder for image, three-column skeleton for grid, single line for footer.
  • Fold line. A dashed border with an inline "fold" label, centred between the above and below tiers. Set hideFoldLine to drop the divider.
  • Coverage overlay. A short strip beneath the mock page — left side prints inline %, right side prints deferred %, with a meter that grows to the inline ratio. Tints green once extracted flips true.
  • Action button. When onToggle is provided, renders a "Extract critical CSS / Reset extraction" toggle on the right. Carries data-cb-armed="true" while the un-optimised state is live so consumers can style the "next action" affordance.

Understanding the component

  1. Fold partition. Zones are partitioned on fold — above zones stack at the top, below zones stack under the fold line. Bytes are summed per tier and surfaced in the coverage overlay.
  2. Tone inversion. Above-the-fold rows paint crisp only once extracted flips true; below-the-fold rows paint crisp in the un-optimised state and dim when extraction lands — that's the visual story for "this content used to load with the page, now it streams in behind the paint".
  3. Illustration registry. kind picks the mini-illustration painted inside each row. Defaults to "block" (a plain skeleton). Heights default to a sensible value per kind and clamp to a 12-72 px range to keep the panel compact.
  4. Motion. Each row crossfades between the crisp and muted tones with the SPRINGS.smooth token, and the coverage meter grows with the same spring. Animations short-circuit under prefers-reduced-motion.

Props

PropTypeDefaultDescription
zonesCriticalCssViewZone[]requiredOrdered list of mock page zones.
extractedbooleanrequiredtrue puts the view in the post-extraction state.
onToggle() => voidOptional click handler for the action button. Omit to hide it.
titleReactNodeOptional heading above the panel.
descriptionReactNodeOptional sub-headline under the title.
actionLabels{ armed: string; disarmed: string }sensible defaultsOverride the action button copy.
unitstring'KB'Display unit suffix for byte counts.
hideOverlaybooleanfalseHide the coverage overlay strip.
hideFoldLinebooleanfalseHide the dashed fold divider.
headingAs'h2' | 'h3' | 'h4''h3'Tag for the title element.
classNamestringMerged onto the root via cn().

CriticalCssViewZone

FieldTypeDescription
idstringStable identifier.
labelReactNodeVisible row label. Pass empty for a chromeless block.
fold'above' | 'below'Which side of the fold the zone lives on.
kind'nav' | 'hero' | 'image' | 'grid' | 'footer' | 'block'Mini-illustration hint. Defaults to 'block'.
heightPxnumberRow height; defaults per kind. Clamped to 12-72 px.
bytesnumberBytes contributed to the inline / deferred totals. Defaults to 0.

Accessibility

  • The wrapper is a <section> with data-cb-edu="critical-css-view" and data-cb-extracted="true | false" mirroring the extraction state.
  • The mock page carries an aria-label describing it as the page layout split by the fold line; the fold divider itself is aria-hidden because the divider text duplicates information that's already conveyed structurally.
  • Every zone row carries an aria-label of the form "Above the fold — 4.7 KB" so screen readers convey both the tier and the byte cost without depending on colour.
  • The coverage overlay lives in an aria-live="polite" region so the percent updates are announced when extracted flips.
  • The action button has visible text, a focus-visible ring, and a subtle active:scale-[0.98] press state.
  • Animations short-circuit under prefers-reduced-motion.

Credits

  • Extracted from: terminal-dreams (src/components/frontend-design/perf-css/ui/CriticalCSSView.tsx). The original was wired to the css-perf-simulator engine (a fixed CSSRuleMock shape with hardcoded aboveFold flags, a built-in rules list, and an FCP callout reading from PerfContext). This rewrite strips the engine coupling and the rules-list double — consumers pass an arbitrary list of { id, label, fold, kind, bytes } zones so the view can model any page layout, and the rules-side of the optimisation lives in the sibling CriticalCssWidget.