Design system and component library
Tokens in a three-layer taxonomy — primitive, semantic, component — wired from design source to code. The hard part is governance: naming, deprecation, and who may add a variant.
Documented component libraryInterface engineering
We build the browser half of your product — rendering strategy, a design system your team can extend, and interaction states that hold up under keyboard, screen reader and a throttled 4G connection.
Front-end work is everything between your API responses and the pixel a user taps: rendering strategy, state and data fetching, a component system, motion, forms, and the long tail of empty, loading and error views that nobody designs but everybody sees. We take that layer on its own terms, whether the back end is ours, yours, or a headless CMS and a commerce API. The durable output is not the screens — it is the component layer underneath them.
Most briefs arrive with a Lighthouse screenshot attached. We do not build against lab scores. We instrument the real thing — Largest Contentful Paint, Interaction to Next Paint and layout shift, collected from actual sessions — and set the budgets against the 75th percentile on the routes that carry revenue. A green lab run on a fast laptop tells you almost nothing about a mid-range phone on a congested network. The same logic governs accessibility: scanners catch a minority of failures, and cannot tell you whether a custom widget is operable by keyboard at all.
| What is true of this work | What it forces | What we do about it |
|---|---|---|
| The runtime is the user’s device | Every kilobyte is a cost | Per-route budgets asserted in CI |
| Scanners miss most WCAG failures | Manual keyboard and screen-reader passes | Both inside the definition of done |
| Design keeps moving after code exists | One change must propagate everywhere | Three-layer tokens, one source of truth |
| Third parties load outside your bundle | Tags can undo any optimisation | Third-party count capped per route |
| Generated UI duplicates rather than abstracts | Four button variants drift apart | Every diff read by a human |
Tokens in a three-layer taxonomy — primitive, semantic, component — wired from design source to code. The hard part is governance: naming, deprecation, and who may add a variant.
Documented component libraryChoosing per route what is static, streamed, server-rendered or client-only, with Suspense boundaries so slow data cannot block the shell. One client boundary too high drags everything beneath it into the bundle.
Rendering and caching planSemantic structure, focus management, live regions and reduced-motion paths, verified by keyboard and screen reader on the real build. Custom comboboxes, date pickers and drag-to-reorder are where compliance actually breaks.
Accessibility remediation logRoute-level limits on JavaScript weight, third-party count and vitals proxies, asserted on every pull request so a regression fails the build instead of surfacing in field data weeks later.
Budget assertions in CIData grids with virtualised rows, multi-step forms that survive a refresh, real-time panels and editors. These are the screens where naive state management shows up as dropped keystrokes and visible input lag.
Interaction state matrixMoving a legacy UI onto a modern stack route by route behind a proxy, so old and new front-ends serve traffic side by side. Big-bang rewrites are how these projects die.
Route migration planWe inventory every route, ranked by traffic and revenue, and pull field data for each. Top routes are walked on a throttled mid-range Android and by keyboard alone, so the brief reflects what users get today.
You getRoute map with per-route budgets
We extract tokens into a three-layer set, document the primitives every screen depends on — button, field, dialog, table, toast — then wire routing and data loading underneath them. The first demo lands on day fourteen.
You getWorking demo on real routes
Screens get assembled from the component layer, never bespoke. Each ships with its empty, loading, error, offline and permission-denied variants, plus responsive behaviour checked at the awkward widths — landscape tablet, 320px phone, 200 percent zoom.
You getScreens with every state covered
Performance budgets, visual regression and automated accessibility checks go into the pipeline and start failing pull requests. We hand over the repository, the component documentation, and a written record of every rendering decision.
You getGreen pipeline and decision log
Server-render by default; pure client apps are the exception.
Anything a user lands on cold should not pay a blank-screen tax while a bundle downloads. Server rendering costs you a runtime and a caching story you now have to reason about, and that price is usually worth paying on public, shareable, indexable routes.
We’d choose otherwise whenusers live inside one long session and neither search engines nor cold first paint matter.
Adopt unstyled accessible primitives; own the styling layer yourself.
Writing your own combobox or date picker means owning years of focus, ARIA and input-method edge cases for no product advantage. A fully themed off-the-shelf kit is the wrong middle ground — you inherit someone else’s design language and fight it forever.
We’d choose otherwise whenthe interaction has no analogue anywhere — a timeline scrubber, a seating map, a waveform editor.
Strangle it route by route behind a router split.
New stack serves the highest-value paths, the old app keeps the rest, and both share tokens and a session. You pay for a proxy layer and a period of two design languages coexisting — cheaper than an eighteen-month rewrite that ships nothing.
We’d choose otherwise whenthe whole surface is a dozen screens, where running two front-ends costs more than rebuilding.
No — hold tokens and states, treat layout as fluid.
Pixel-parity at three fixed widths is a standard that fails at every width in between. The design file stays the source of truth for tokens, spacing scale and component states; where a comp and a real string length disagree, the string wins.
We’d choose otherwise whenit is an art-directed campaign page where copy is frozen and every breakpoint is drawn by hand.
You do, completely — repository, tokens, component library, CI configuration and documentation, with full IP transfer on final payment. There is no runtime licence, no hosted service, and nothing that phones home. The component library is a normal package in your own registry, so your team or another vendor can pick it up without asking us for anything.
Scope is fixed before we start, so the price does not move unless you change the brief. The three things that inflate front-end estimates are all avoidable: design that arrives incomplete and gets decided during implementation, custom interactive widgets that need full accessibility work, and an API still changing shape. We price those explicitly at the audit.
Not unconditionally — no one honest can. We control bundle weight, render path, image handling, font loading and hydration cost. We do not control your third-party tags, your ad stack or a slow API, and those dominate field measurements. We commit to budgets held in CI, a documented blocker list per metric, and fixes for everything we own.
We generate much of the implementation and review all of it. Generated UI is fast at screens and unreliable at systems — it duplicates rather than abstracts, invents a fourth button variant, and writes markup that reads badly to a screen reader. Our gates exist for that: accessibility assertions, visual regression, a human on every diff.
A 30-day warranty covers defects against the agreed scope at no cost — we fix them, not schedule them. Beyond that, the useful protection is the pipeline we leave behind: visual regression catches a component change that silently moved a layout, and the budget and accessibility assertions fail the pull request first. Ongoing work runs as a separate retainer.
Thirty minutes with the engineers who would build it. You leave with a scope, a timeline and a fixed price — or an honest no, and the reason why.