Speed is a feature. Performance is the foundation of user trust. Latency kills flow.
You can't fix what you can't measure. Guesswork leads to optimisation of the wrong things.
Development machines lie. A fast laptop on fibre hides the problems your users face.
Do
Disable extensions. Use CPU and network throttling to simulate real devices. Profile in an incognito window.
Don’t
Don't profile on a high-end machine with a fibre connection and assume it's fine.
Three metrics that define real-world user experience. Target green on all three.
Stability is quality. Things should not jump around as they load.
Do
Set explicit dimensions on all images and media. Reserve space for content that loads asynchronously.
Don’t
Don't let an image push text down the page when it finally loads, or inject content above the viewport without reserving space.
Prioritise the viewport. Bandwidth should be spent on what is seen immediately.
<!-- Preload above-the-fold images --><link rel="preload" href="/hero.jpg" as="image" /><!-- Lazy-load everything else --><img src="footer.jpg" loading="lazy" alt="..." />
Do
Preload above-the-fold images. Lazy-load everything below the fold.
Don’t
Don't lazy-load the Largest Contentful Paint image, causing a visible delay on the most important element.
For Oztix-hosted imagery the Image component handles
all of this: explicit dimensions to prevent CLS, a right-sized WebP srcSet to
cut bytes, lazy-by-default loading with priority for the LCP image, and
defer for off-screen carousel slides.
The main thread is for UI. Heavy logic belongs elsewhere.
Do
Move expensive calculations or data processing to Web Workers. Break long
tasks into smaller chunks with requestIdleCallback or
scheduler.yield().
Don’t
Don't freeze the UI while parsing a large JSON file or running an expensive sort on the main thread.
Reactivity has a cost. The DOM is slow. Minimise the work the browser has to do.
Unnecessary renders burn battery and block interaction.
Do
Use React DevTools or React Scan to identify and minimise re-renders. Colocate state near where it's used.
Don’t
Don't assume functional components are cheap enough to re-render constantly. A parent re-rendering cascades to every child.
Reading and writing layout properties triggers expensive reflows.
Do
Batch DOM reads and writes. Animate with transform and opacity
(compositor-only properties) instead of width, height, or top.
Don’t
Don't read a width, set a width, then read it again in a loop (layout thrashing).
DOM nodes are heavy. Don't render what the user can't see.
/* Use virtualisation or CSS containment */<VirtualList items={items} />/* Or use CSS containment for simpler cases */.offscreen { content-visibility: auto; }
Do
Use virtualisation (such as virtua) or content-visibility: auto for
long lists and large tables.
Don’t
Don't render 10,000 rows in a table just because the API returned them.
Latency kills flow. API interactions should feel instantaneous.
Set expectations for how fast things should be.
Do
Ensure POST, PATCH, and DELETE requests complete in under 500ms. Use optimistic UI for fast, reversible actions so the interface moves at the speed of thought.
Don’t
Don't block the UI for 2 seconds while waiting for a database write.
Handshakes take time. Establish connections before you need the data.
<link rel="preconnect" href="https://cdn.oztix.com.au" /><link rel="dns-prefetch" href="https://api.oztix.com.au" />
Do
Use <link rel="preconnect"> for critical CDNs or API domains.
Don’t
Don't wait until JavaScript requests a font before opening the connection to the font server.
Typography should not block reading. Text must appear fast. See Typography for the full type system.
Custom fonts are a luxury the user pays for with load time.
Do
Preload critical fonts. Subset fonts to only include used characters (such
as with unicode-range). Use font-display: swap so text is visible
immediately.
Don’t
Don't load a 5MB font file containing every language in the world for an English site.
The design system already takes care of several performance concerns. You get these for free.
Sizes text-lg and above use clamp() for fluid scaling. No manual
breakpoint overrides needed.
Intent, emphasis, and interaction utilities are pure CSS. No JavaScript runtime cost for styling.
Components are built with tsdown in unbundle mode. Every leaf compiles to
its own dist file, so subpath imports only drag in what you use.
A global prefers-reduced-motion reset neutralises all transitions and
animations automatically.
How performance rules map to existing foundation pages.
| Rule | Foundation | What it covers |
|---|---|---|
| No CLS | Layout | Grid defaults, explicit sizing, and gap over margin |
| Font optimisation | Typography | Fluid scaling, font families, and preloading |
| Compositor animations | Motion | Transform and opacity transitions, and motion tokens |
| Reduced motion | Motion | Global prefers-reduced-motion reset |
| Optimistic UI | Interactions | Loading states and feedback patterns |