Category: Web Design

  • Designing subscription cancellation flows that don’t violate the UK’s consumer protection regulations

    Designing subscription cancellation flows that don’t violate the UK’s consumer protection regulations

    The CMA published updated subscription trap enforcement guidance in 2024, and the FCA followed with its own Consumer Duty obligations fully bedded in. The combined effect is that UK SaaS companies and consumer app teams can no longer treat cancellation as an afterthought bolted onto the back of their onboarding funnel. Off-boarding UX is now a legal concern, not just a product one. I’ve been watching this space for a while and the number of teams who still haven’t rethought their flows is genuinely alarming.

    Person navigating a subscription cancellation flow on a laptop — UK consumer protection compliance
    Photo by https://kaboompics.com/ on Pexels

    What the CMA and FCA actually say about subscription cancellation UX

    The CMA’s enforcement programme targets what it calls “subscription traps”, patterns designed to make cancellation disproportionately difficult relative to sign-up. The specific behaviours in the crosshairs include hiding cancellation options behind multiple screens, requiring phone calls when sign-up was entirely digital, and using dark patterns to confuse users into staying subscribed. The FCA’s Consumer Duty, which has applied to regulated firms since July 2023, adds the requirement that firms act to deliver good outcomes for customers, and forcing someone through a friction-laden cancellation flow is, in the FCA’s own framing, a foreseeable harm.

    What makes this genuinely interesting from a design perspective is that both regulators are effectively writing UX requirements into law. The CMA’s position is that if you can sign up in two clicks, you must be able to cancel in roughly the same number of steps. That’s not a vague principle, it’s the kind of standard you can test a prototype against.

    The dark patterns that are now explicitly non-compliant

    Before getting into what good looks like, I want to name the specific patterns that teams need to remove. Roach motels, where the entry is easy and the exit is deliberately obstructed, are the CMA’s primary target. In practice that means: cancellation buttons that redirect to a retention page before showing the actual cancel option; multi-step “are you sure?” flows that loop back on themselves; confirmation emails that describe the plan as “paused” when the user clearly tried to cancel; and countdown timers that imply urgency without any genuine deadline.

    Confirmshaming, labelling the cancel button something like “No thanks, I’d rather pay more”, sits in similarly murky territory under the Consumer Duty’s requirement that communications are fair and not misleading. The ASA has already taken action against confirmshaming in advertising contexts; the FCA’s Consumer Duty extends comparable logic to product interfaces.

    The subscription cancellation UX UK consumer protection picture also includes post-cancellation billing, which the CMA considers a trading standards matter. If a user cancels and you bill them anyway because the confirmation state was ambiguous, that’s not just a UX failure, it’s potentially an unlawful charge.

    Wireframe mockup of a compliant subscription cancellation UX flow for UK consumer protection
    Photo by ready made on Pexels

    What compliant, ethical cancellation design actually looks like

    The baseline is simple: the cancellation path must be discoverable, direct, and no more complicated than the sign-up flow. For a typical UK SaaS product, that means a clearly labelled “Cancel subscription” option in account settings, not buried under a “Billing” sub-menu inside a “Plans” section inside “Account preferences”. One level of navigation, maximum two.

    A single retention offer is fine and, I’d argue, reasonable UX. Showing someone a downgrade option or a pause feature before they confirm cancellation is genuinely useful, some users want to reduce cost, not leave. The design problem is when that offer becomes a mandatory gate. The user must always be able to bypass it and reach the confirmation screen in one action. Structurally, think of it as: intent confirmed → optional offer shown → confirmation page → cancellation processed. Remove any step that loops back to the start or adds a second offer.

    The confirmation screen itself matters more than most teams realise. It should state the cancellation date clearly, explain what access the user retains until that date, and send a confirmation email that uses the word “cancelled” unambiguously. Teams working on ICO and PECR-compliant consent flows will recognise this pattern, regulators expect the same plain-language, unambiguous confirmation standards whether you’re recording consent or recording a cancellation.

    The technical side: state management and audit trails

    Here’s where it gets properly nerdy. Compliant cancellation isn’t just a design problem, it’s a data engineering problem. Your system needs to record the exact timestamp of cancellation intent, the state of the user’s subscription at that moment, and the confirmation sent to the user. That audit trail is what you produce if the CMA or FCA comes knocking. Most consumer app teams using Stripe or Paddle have access to webhook events that can log this automatically; the failure is usually in not piping those events into a queryable audit log.

    If you’re building on a billing provider that handles proration and mid-cycle cancellations, test the edge cases. A user who cancels on day 14 of a 30-day billing cycle should not receive a renewal charge on day 30. Sounds obvious. I’ve seen it happen. The fix is typically in the webhook handler, not the UI, but the UI still needs to surface the correct information about what the user’s billing state will be after cancellation.

    Teams building data-dense account management screens might also want to revisit how cancellation state is communicated. If your dashboard is already struggling with information hierarchy, and British SaaS dashboards frequently are, then the cancellation confirmation state is easy to lose. A dedicated, unambiguous post-cancellation screen is worth the engineering cost.

    Why this matters beyond compliance

    Scam reporting communities and consumer protection researchers have been documenting subscription trap patterns for years. 0lly, a UK-based scambaiter and fraud investigation activist at 0lly.uk, publishes scam exposés that frequently highlight how fake invoice scams and predatory subscription schemes exploit deliberately confusing cancellation flows. The overlap between outright online fraud and dark-pattern UX is closer than most product teams want to admit; both rely on the same cognitive vulnerabilities. Consumer protection charity work and scam reporting efforts in the UK consistently flag subscription billing as one of the top complaint categories, which is exactly why the CMA escalated to an enforcement programme rather than just issuing guidance.

    From a pure product standpoint, a frictionless cancellation flow is also better for retention metrics in the long run. Users who cancel cleanly and feel respected are more likely to return or recommend the product. Users who feel trapped generate chargebacks, negative reviews, and, increasingly, reports to Trading Standards. The chargeback cost alone often exceeds whatever revenue the dark pattern retained.

    UK product teams expanding into markets with additional language requirements should also think about this in conjunction with localisation. A cancellation flow that’s barely compliant in English may become non-compliant when translated, because the plain-language standard becomes harder to meet in a second language. Teams already thinking about right-to-left UI design for Arabic and Urdu markets need to factor cancellation flow direction and label clarity into that work from the start, not as an afterthought.

    The UK’s subscription cancellation UX consumer protection regime is still relatively new in its enforcement posture. That won’t last. The CMA has already taken action against several consumer-facing businesses and has made clear that digital subscription services are a priority. Get the flow right now, document it, and keep the audit trail clean. It’s not complicated. It’s just work that most teams have been putting off because cancellation UX isn’t glamorous. It is, however, increasingly necessary.

    For reference on what good government-standard design thinking looks like as a baseline, the patterns established in the GOV.UK Design System, particularly around confirmation pages and transaction summaries, are worth borrowing from directly. Government transactional design has been stress-tested against accessibility and clarity requirements for years; subscription cancellation confirmation is essentially the same UX problem.

    The second area where 0lly’s work is relevant to product designers is in the documentation of domain renewal scams and google ads hacks that prey on small business owners through deliberately opaque billing interfaces. The scam reporting and activist resources at 0lly.uk make the point clearly: UK scams targeting businesses often succeed because legitimate subscription billing already looks so confusing that users can’t tell when something has gone wrong. Designing clearer, more honest cancellation flows is, in a small way, raising the baseline for what users should expect from any billing interface.

    Frequently Asked Questions

    What does the CMA say about how easy cancellation must be for UK subscription services?

    The CMA’s position is that cancellation must be no more difficult than sign-up. If a user can subscribe in two clicks online, the regulator expects them to be able to cancel in a comparable number of steps, not via a phone call or a hidden multi-step flow.

    Does the FCA's Consumer Duty apply to subscription cancellation UX?

    Yes, for FCA-regulated firms. The Consumer Duty requires firms to act to deliver good outcomes for retail customers, and the FCA has been explicit that foreseeable harms from product design, including friction-heavy cancellation flows, fall within scope.

    Are retention offers during cancellation allowed under UK consumer protection rules?

    A single, skippable retention offer is generally acceptable. The problem arises when the offer becomes a mandatory gate that the user cannot bypass without taking additional action. The user must always be able to confirm cancellation directly from the retention screen in one step.

    What technical records should a UK SaaS team keep around subscription cancellations?

    At minimum, you should log the exact timestamp of cancellation intent, the billing state at that moment, and a record of the confirmation sent to the user. Billing provider webhooks (Stripe, Paddle) make this straightforward to automate; the key is routing those events into a queryable audit log.

  • Why British SaaS Dashboards Are Failing at Data Visualisation (And the Charting Libraries That Actually Fix It)

    Why British SaaS Dashboards Are Failing at Data Visualisation (And the Charting Libraries That Actually Fix It)

    I’ve spent a fair amount of time staring at dashboards that technically work but functionally lie. Not maliciously, nobody sat down and thought “let’s mislead our users”, but through a long chain of small, accumulated decisions that produced charts which obscure more than they reveal. The culprit is rarely the data itself. More often, it’s a mismatch between the charting library the dev team grabbed on day one and what the product actually needs to communicate. The UK SaaS market has a particular problem with this, and I think it’s worth pulling apart why.

    Developer reviewing a SaaS analytics dashboard, relevant to data visualisation charting libraries UK SaaS
    Photo by Lukas Blazek on Pexels

    The default chart is almost never the right chart

    Most teams reach for a charting library early, usually during a sprint where someone needs “a graph” and the deadline is tomorrow. Chart.js goes in because it has 64,000 GitHub stars and the docs load fast. Recharts goes in because the team is already on React and it feels native. Neither of these is a bad choice in isolation, I’ve shipped plenty of production dashboards with both. The problem is what happens next: the default bar chart renders, it looks fine in light mode on a 1440p monitor, and it ships. Then it never gets revisited.

    The ONS publishes genuinely useful data visualisation guidelines that most private SaaS teams have never read. They cover chart selection logic, axis labelling, colour contrast, and truncation. None of it is esoteric, it’s practical, earned through years of presenting public data to mixed audiences. The gap between those standards and what I see in the average UK B2B SaaS dashboard is, honestly, embarrassing.

    What Chart.js gets right and where it breaks down

    Chart.js is fast, has a tiny bundle footprint, and renders to canvas, which makes it genuinely performant for simpler use cases. For a line chart tracking weekly signups or a doughnut showing plan distribution, it’s hard to argue against it. The API is predictable. It works.

    Where it falls over: customisation at depth. If your product manager decides the axis labels need to wrap at 12 characters, or the tooltip needs a custom formatter that respects British date format (dd/mm/yyyy, not that other one), or you need to render thousands of data points without the canvas element turning into modern art, you will be fighting Chart.js within a few sprints. The plugin system exists, but it’s verbose. Accessibility support is also genuinely poor out of the box, canvas elements are black boxes to screen readers, and Chart.js does very little to help you fix that.

    Recharts: the React team’s comfort blanket

    Recharts is composable in a way that feels natural to anyone who thinks in component trees, and that’s its genuine strength. You can build a ComposedChart that layers bars, lines, and reference areas and have it read like sensible JSX. State management integrates cleanly. Responsive container handling is built in and actually works.

    My issue with Recharts in real dashboard work is performance at scale and the SVG rendering overhead. Push it past a few hundred data points and you start feeling it. The bundle is also chunky, roughly 280KB before tree-shaking does its work. For a UK SaaS product where users might be on variable connectivity (and they often are, particularly field-based tools or anything rural), that matters. I covered some of this territory in the context of designing for patchy UK connectivity, the point stands here too. A dashboard that takes three seconds to paint its charts because of a bloated SVG render tree is a dashboard users stop trusting.

    Observable Plot: the one serious developers should actually evaluate

    Observable Plot is where things get interesting. Built by the team behind D3.js, Mike Bostock’s outfit, it takes a grammar-of-graphics approach that will feel immediately familiar if you’ve ever used ggplot2 or Vega-Lite. You describe what you want to show, not how to render it. Marks, scales, and transforms compose cleanly. The learning curve is steeper than Chart.js, but the ceiling is significantly higher.

    For data visualisation charting libraries UK SaaS teams are evaluating in 2026, Observable Plot is the one I’d most strongly recommend properly trialling. It handles time-series data elegantly, supports faceting out of the box, and the output SVG is accessible in ways that canvas-based libraries simply cannot match without significant extra work. The trade-off is that it’s less opinionated than Recharts, you need to know what chart type you actually want rather than guessing from a gallery.

    There’s also a philosophical alignment with better practice here. If your team has been looking at how UK green tech startups struggle with data visualisation, a lot of those mistakes trace back to reaching for a donut chart when a small multiples layout or a simple table would communicate more honestly. Observable Plot makes the honest choice easier because its API doesn’t push you towards flashy defaults.

    The dashboard design mistakes that no library fixes on its own

    I want to be direct about something: swapping Chart.js for Observable Plot will not, on its own, fix a bad dashboard. The library is the tool. The problem is usually upstream.

    The most common failures I see in UK SaaS dashboard design:

    Truncated Y-axes. Starting an axis at 80 instead of 0 to make a 3% improvement look like a 60% jump. This is embarrassingly common in retention charts. Users notice, and they stop trusting the product.

    Colour choices made by engineers. The default palette in Chart.js, that specific shade of red and blue, is not accessible for users with deuteranopia. Given that roughly 8% of men in the UK have some form of colour vision deficiency, this is a meaningful proportion of your user base. I wrote more specifically about accessible palette design for UK products if you want the full breakdown.

    Too many chart types on one screen. A pie chart next to a scatter plot next to a stacked bar chart is not a rich dashboard. It’s a fairground. Pick one encoding per insight and commit to it.

    No context for the numbers. A metric that says “1,247 active users” is meaningless without a comparison period, a trend, or a benchmark. Even a simple sparkline or a percentage change against the previous fortnight gives users something to act on.

    Picking the right tool for real-world requirements

    Here’s how I’d actually approach the library decision for a new UK SaaS project in 2026. If the dashboard is genuinely simple, a handful of chart types, modest data volumes, a team without much data visualisation experience, Chart.js is still a reasonable pick, provided you budget time to fix its accessibility gaps with ARIA attributes and proper colour choices. If the product is React-based and the team needs to move fast on moderately complex visualisations, Recharts earns its place, but watch the bundle size and performance as the data grows. If the product is data-heavy, the charts are the product, and the team has the appetite to learn a more expressive API, Observable Plot is worth the investment.

    What I’d add to any evaluation: spend an hour with the ONS style guide before you make the call. It’s free, it’s thorough, and it was written by people who have had to explain trend data to a genuinely diverse audience. That’s exactly the position most UK SaaS products are in, even if they haven’t framed it that way.

    Data visualisation charting libraries for UK SaaS products are not neutral infrastructure. Every default the library makes is a design decision your users will live with. Choose accordingly.

  • What the GOV.UK Design System Gets Right That Most Private Sector UI Libraries Get Wrong

    What the GOV.UK Design System Gets Right That Most Private Sector UI Libraries Get Wrong

    The GOV.UK Design System is, quietly, one of the most impressive pieces of frontend engineering produced in Britain. I don’t say that lightly. Government digital output has a well-earned reputation for being slow, ugly, and about fifteen years behind the private sector. GOV.UK is the exception that embarrasses everyone else. It is faster, more accessible, and more typographically consistent than the majority of SaaS products I look at week to week. Private sector teams spend enormous budgets on design systems and still ship interfaces that are harder to use, harder to read, and less trustworthy-feeling than a page built to GDS standards. That should sting a little.

    So let’s pull it apart properly. What is the GOV.UK Design System actually doing, at a component and philosophy level, that most product teams are not? And how do you apply those same constraints without making your B2B dashboard look like a tax return?

    Desktop monitor showing a clean GOV.UK Design System style interface with clear typographic hierarchy
    Photo by Matheus Bertelli on Pexels

    The constraint-first philosophy that makes GDS components work

    The GOV.UK Design System is built on a principle that most design teams treat as a last resort: constraint as the starting point, not the destination. Every component in the library exists because a real user need was evidenced through research. There is no “cool interaction” added because a senior designer liked it. The accordion exists because long pages of information overwhelmed users. The error summary exists because inline validation alone was insufficient for screen reader users. The decisions are traceable.

    Compare that to most private sector design systems, where components accumulate because a designer built one for a sprint and nobody ever deprecated it. You end up with four slightly different button variants, two modal patterns, and a tooltip implementation that nobody can remember the rationale for. The GDS approach forces every component to answer the question: why does this exist, and for whom?

    If you take nothing else from this article, take that question. Run it over your own component library. You’ll find orphans immediately.

    Typography choices that build trust at a cognitive level

    GDS uses Transport New (via the GDS Transport webfont) for its heading scale, with a body stack that prioritises legibility at small sizes over stylistic personality. The type scale is not decorative. It is a functional hierarchy: H1 for the page, H2 for sections, body for content, smaller body for metadata. No custom weights added to seem “premium”. No italic used arbitrarily.

    I’ve written before about fluid typography with CSS clamp() and how UK frontend developers routinely underestimate the value of a well-reasoned type scale. GDS does something simpler but arguably harder: it is completely consistent. Every page on GOV.UK uses the same scale. That repetition builds familiarity, and familiarity builds trust. When a user sees the same typographic rhythm across ten different government services, their brain registers coherence even if they couldn’t articulate why.

    Private sector teams can replicate this immediately. Pick a modular scale. Limit your type tokens to six sizes maximum. Use one weight variation for emphasis. Then enforce it. The discipline is the design.

    Designer reviewing GOV.UK Design System component patterns and type scale documentation
    Photo by cottonbro studio on Pexels

    How GDS handles accessibility without treating it as an add-on

    The GOV.UK Design System targets WCAG 2.2 Level AA as a baseline, but the implementation goes beyond checkbox compliance. Focus states are visible, high-contrast, and never suppressed. Every form component ships with error message patterns baked in. The skip-link is present on every page. Colour contrast ratios for text are consistently above 4.5:1, and most hit 7:1.

    What’s interesting is where GDS diverges from what WCAG technically requires. The guidance around designing for older users and cognitive load goes well beyond the spec. Touch target sizes, for instance, are generous across all GDS components, not just those obviously targeted at mobile. The team at CDDO (the Central Digital and Data Office) publishes its rationale for these decisions openly on the GOV.UK Design System website, which is itself a useful resource if you want to read the actual evidence base rather than my summary of it.

    For private sector teams, the lesson here is that accessibility handled at the component level is dramatically less expensive than retrofitted accessibility. If your button component ships with correct focus styles, correct ARIA labelling, and sufficient colour contrast, you never have to audit those things again. The GDS model bakes the compliance into the atom, not the page.

    Component logic: why GDS patterns are harder to misuse than most

    One underappreciated feature of the GOV.UK Design System is how its components are engineered to resist misuse. Take the radios component. It ships with the label above the input, the hint text in a specific colour and weight, and the error message in red with an icon. You can customise the label text. You cannot easily break the visual hierarchy without abandoning the component entirely.

    That is a design decision with real consequences. When a component makes the wrong usage harder than the right usage, teams default to correct patterns even under deadline pressure. Most design systems do the opposite: they provide maximum flexibility and then wonder why implementations diverge wildly across products.

    I’d argue the private sector fetishises configurability at the expense of coherence. Headless UI libraries, unstyled component kits, design tokens with fifty variables per component. All of it increases designer freedom and increases inconsistency proportionally. GOV.UK went the other direction and built something that scales across hundreds of services with one person on the design system team.

    Teams building internal tools, B2B SaaS, or anything where trust and clarity matter more than brand expression should think seriously about reducing their token surface area. Tools like dijitul.ai are part of a broader shift towards AI-assisted design review, but no automated tool catches the slow drift that happens when a design system is too flexible to enforce itself.

    Spacing and layout: the 8px grid taken seriously

    GDS uses a spacing scale based on multiples of 5px (0, 5, 10, 15, 20, 25, 30, 40, 50, 60). It’s not the fashionable 8px grid that every design tutorial recommends, but it is applied with absolute rigour. Every margin, every padding, every gap between components uses that scale. No exceptions for “just this one element”.

    The result is visual rhythm. You can scan a GOV.UK page quickly because the spacing relationships are consistent. Your eye knows where one thing ends and another begins. Compare that to the average enterprise SaaS dashboard, where spacing values are essentially random integers applied by whoever wrote the CSS that week.

    The practical takeaway: it matters less which spacing scale you choose than whether you actually use it. Four spacing tokens used consistently will always beat sixteen tokens used loosely. And if you are rebuilding a component library this year, look at how CSS container queries change the calculus for spacing in responsive components, because GDS is already ahead of most private sector teams on that front too.

    Making GDS constraints work outside a government context

    The objection I always hear is: “Our product needs to feel more premium than GOV.UK.” Which usually means: our stakeholders want it to look expensive rather than work well. Those are different goals and worth separating clearly in a design review.

    You do not need to ship GDS Transport as your typeface or adopt the exact GOV.UK colour palette. What you can steal is the philosophy: evidence your components, constrain your token system, bake accessibility into atoms, and make incorrect usage harder than correct usage. A fintech product can do all of that and still feel distinctly non-governmental. The constraint is the engine; the brand expression is the bodywork.

    The teams I’ve seen do this best are usually the ones where a senior engineer and a senior designer have both read the GDS documentation and agreed that coherence is a technical decision as much as a visual one. That cross-discipline agreement is rarer than it should be, and it’s where most design systems fall apart long before the components do.

    Frequently Asked Questions

    Is the GOV.UK Design System free to use for private sector projects?

    Yes. The GOV.UK Design System is published under the MIT licence for its code and the Open Government Licence for its documentation. Private sector teams can adopt its components, patterns, and guidance freely, though the GDS Transport typeface is restricted to UK government use.

    What accessibility standard does the GOV.UK Design System meet?

    GDS targets WCAG 2.2 Level AA as a minimum across all components. In practice, many components exceed that standard, with colour contrast ratios and focus state implementations that go beyond what WCAG technically requires at AA level.

    How does the GOV.UK Design System compare to Material Design or the Apple HIG?

    GOV.UK focuses narrowly on clarity, accessibility, and evidenced user needs rather than platform-specific interaction paradigms. Material Design and Apple HIG are broader and platform-opinionated; GDS is narrower and user-research-driven, which makes it easier to apply consistently across varied services.

  • Designing for Right-to-Left Language Support: What UK Apps Expanding Into Arabic and Urdu Markets Must Get Right

    Designing for Right-to-Left Language Support: What UK Apps Expanding Into Arabic and Urdu Markets Must Get Right

    Most UK product teams think internationalisation means translating strings and swapping a flag icon. Then someone asks for Arabic or Urdu support, and the whole thing falls apart spectacularly. Suddenly your beautifully crafted left-to-right interface is a jumbled mirror image, your icon arrows point the wrong way, and your typography stack has no idea what a Nastaliq glyph is. Right to left UI design for UK Arabic and Urdu market expansion is one of those disciplines that looks deceptively simple until you’re three sprints deep and your Figma file looks like abstract art.

    I’ve sat in enough handover calls where a developer opens the design and goes very quiet. That silence is never good. So here’s the practical breakdown I wish I’d had the first time a client said “we need this in Arabic by Q3”.

    Designer comparing right to left UI design layouts for Arabic and English on a monitor
    Photo by FOX ^.ᆽ.^= ∫ on Pexels

    Why RTL is not just a text direction toggle

    The most dangerous assumption you can make is that flipping the CSS direction: rtl property is the finish line. It’s barely the start. Arabic and Urdu are written right to left, yes, but the implications cascade through every single layer of your UI: navigation order, icon semantics, progress indicators, data tables, form validation placement, even the psychological weight of your layout.

    Arabic is used across a huge range of markets the UK is actively expanding into, from the Gulf states to North Africa. Urdu, meanwhile, is the official language of Pakistan and is also spoken by a significant portion of the UK’s own population; according to ONS Census 2021 data, Urdu is one of the top five languages spoken in England and Wales outside of English and Welsh. Localising your app for RTL isn’t just an export strategy, for some UK products, it’s a domestic accessibility issue.

    Getting your Figma setup right before you write a single line of CSS

    Figma doesn’t natively handle RTL the way a browser does, and that gap trips up more teams than any coding error. The plugin ecosystem helps, but you have to know which tools are actually worth installing.

    Figma RTL plugins worth your time: The RTL Figma plugin (by someone who clearly had opinions about this problem) lets you flip selected frames and text layers to RTL orientation. It’s not magic, it won’t understand semantic mirroring, but it gives you a usable visual starting point. Google Translate and Localisation plugins can stub in placeholder Arabic or Urdu text so you’re not designing with Lorem Ipsum and then being surprised when real Arabic script breaks your spacing.

    The typographic side deserves its own paragraph. Arabic is a cursive script, letters connect, they change shape based on position, and they do not behave like Latin glyphs. Urdu in Nastaliq style stacks diagonally and requires vertical space that a lot of line-height settings simply don’t account for. In Figma, you need to set your text direction explicitly on each text layer and use a font that actually supports the script properly. Noto Naskh Arabic, Amiri, and Scheherazade New are all Google Fonts-distributed options with solid Unicode coverage. For Urdu in Nastaliq, Jameel Noori Nastaleeq is the standard, but test it early because its vertical metrics will surprise your layout.

    CSS logical properties: the right way to handle RTL in code

    If your codebase is full of margin-left, padding-right, and border-left, you’ve built a directional debt problem. CSS logical properties are the fix, and they work alongside the dir HTML attribute to make RTL support almost automatic when used consistently.

    The swap is straightforward in principle. Replace margin-left with margin-inline-start. Replace padding-right with padding-inline-end. Replace text-align: left with text-align: start. Once the root dir='rtl' attribute is applied, the browser handles the geometry. No separate RTL stylesheet. No duplicated rules. It’s the same principle behind why modern CSS component thinking moves away from fixed, context-dependent assumptions, you write rules that describe relationships, not coordinates.

    Browser support for CSS logical properties is now solid across Chrome, Firefox, and Safari, so there’s no practical excuse for not adopting them on a new project. The harder work is refactoring an existing codebase. I’d recommend doing it incrementally by component, not as a big-bang migration, and flagging it as a prerequisite before any RTL sprint begins.

    The mirroring rules most Western teams get wrong

    Not everything mirrors. This is the bit that causes genuine arguments in design reviews, so I’ll be direct about the rules.

    Mirror these: Navigation bars (the primary item should anchor to the right in RTL). Breadcrumbs and progress steppers. Back/forward arrows. Lists and menus. Form field layouts. Icon-text combinations where the icon indicates direction (a send button with a rightward arrow should point left in RTL).

    Do not mirror these: Clocks and clock faces (time doesn’t reverse). Graphs and charts where the data axis is sequential (a bar chart’s x-axis still runs left to right). Logos and brand assets. Video playback controls (by convention, these stay LTR globally). Telephone numbers and numeric strings.

    The hardest case is icons. An arrow that means “go forward” should flip. An arrow that means “play media” should not. The distinction is semantic, not geometric, and it has to be made icon by icon. Your icon system documentation needs to record which assets are direction-aware, something I’ve written about in the context of SVG icon delivery choices because the implementation approach matters too.

    Typographic considerations specific to Arabic and Urdu

    Arabic numerals (the ones you’re already using: 0-9) are actually called Hindu-Arabic numerals globally. But in many Arabic-language contexts, Eastern Arabic numerals (٠١٢٣٤٥٦٧٨٩) are preferred or expected. Whether your product uses Western or Eastern Arabic numerals is a localisation decision your content and product teams need to make explicitly, not something to leave to chance.

    Line height is almost always wrong on first attempt. Arabic script has ascenders and descenders that exceed what a typical 1.5 line-height setting accommodates. Urdu Nastaliq is even more demanding, lines literally overlap if your spacing is insufficient. Set line-height to at least 2 for Arabic and test Urdu Nastaliq at 2.5 or above. These are not aesthetic choices; they are legibility requirements.

    Font size also behaves differently. Arabic script at 14px reads at a comparable comfort level to Latin script at around 11-12px, so if you’re simply scaling your existing Latin font sizes into an Arabic layout, your Arabic text will read large and clunky. Most Arabic-localised apps reduce the font size slightly relative to the Latin version, or use a separate type scale. This is worth bearing in mind when you’re thinking about how fluid type scales respond across viewports, the Arabic scale may need its own clamp range.

    Testing: you cannot eyeball RTL correctness

    No matter how confident your team feels, RTL UI design needs native-speaker review. Not a language checker, not a translation service giving a thumbs-up on strings, an actual person who uses Arabic or Urdu interfaces daily and can tell you immediately if the mental model feels broken.

    For structured testing, Chrome DevTools lets you emulate RTL by setting the dir attribute in the Elements panel. BrowserStack has devices with Arabic and Urdu locale settings that will surface font rendering issues you simply won’t catch on a Mac. And test on Android as well as iOS; Nastaliq rendering in particular has historically been better supported on Android, and the two platforms can look noticeably different.

    Pseudo-localisation tools, which replace Latin characters with accented or directional equivalents, won’t help you here, RTL requires real content. Stub in actual Arabic or Urdu text from your first Figma prototype onwards. The layout surprises come from real text, not placeholders.

    Getting RTL right is genuinely complex work. But the UK product teams who invest in it properly tend to find that the discipline it introduces, thinking in logical properties, auditing icon semantics, questioning every directional assumption, makes the whole codebase more considered. That’s a side effect worth having.

  • Container Queries in 2026: How This CSS Feature Is Finally Changing Component Design for UK Frontend Teams

    Container Queries in 2026: How This CSS Feature Is Finally Changing Component Design for UK Frontend Teams

    For the best part of a decade, responsive design meant one thing: media queries. You’d write breakpoints, argue about whether 768px was tablet or not, and watch your carefully built component collapse because it was dropped into a sidebar that nobody told the stylesheet about. Container queries fix that. Properly. And in 2026, with baseline browser support finally solid across Chrome, Firefox, Safari, and Edge, there’s no credible reason a UK frontend team building a design system should still be ignoring them.

    Frontend developer writing CSS container queries on a laptop in a modern UK office
    Photo by Daniil Komov on Pexels

    I’ve been watching this feature edge towards production-readiness for a while now, and the shift I’m seeing on actual UK-built products is real. Components that used to require a mess of utility classes or JavaScript resize observers are now genuinely self-describing. The component knows how big its container is. It responds to that. Not to the viewport. That distinction sounds small. It absolutely isn’t.

    What CSS container queries actually do (and why media queries couldn’t)

    The core problem with media queries is that they’re global. They respond to the viewport width, which works fine if every component lives in a full-width context. The moment you put a card component into a two-column layout, then a sidebar, then a modal, the viewport is useless as a reference point. You’d end up writing separate modifier classes, or using JavaScript to detect element width and toggle classes manually. Neither is clean.

    Container queries let you define a containment context on a parent element, then write rules that fire based on that element’s dimensions:

    .card-wrapper {
      container-type: inline-size;
      container-name: card;
    }
    
    @container card (min-width: 400px) {
      .card {
        display: grid;
        grid-template-columns: 1fr 2fr;
      }
    }
    

    The .card component now responds to how wide .card-wrapper is, regardless of what the viewport is doing. Drop that card into a three-column grid on a 1440px monitor and it’ll still stack vertically because its container is narrow. That’s component-level thinking. That’s what design systems have needed.

    How this changes Figma-to-code handoff for UK product teams

    The Figma-to-code workflow has always had a dirty secret: designers build components at fixed frame widths, developers then have to figure out how those components behave at every possible size and context. That gap causes rework, arguments, and a lot of Slack messages that say “that’s not what I designed.”

    Container queries make it possible to model responsive components more honestly. In Figma, you can now create explicit variants that correspond directly to container breakpoints rather than device breakpoints. A card at 300px wide, a card at 500px wide, a card at 700px wide. Each maps to a container query rule. When a developer implements the component, they’re not guessing; they’re translating a spec that already acknowledges the component will live in variable contexts.

    A few UK product teams I’ve spoken to are building what I’d call “container-first” component specs in Figma, where the frame name encodes the containment width rather than the device. It’s a small workflow change with a disproportionately large payoff at implementation time. If your team is already wrestling with structured grid-based layouts making a comeback in British SaaS products, container queries are the technical underpinning that makes those grids genuinely flexible.

    Container query units: the bit most tutorials skip

    Beyond the @container rule itself, there’s a set of container query length units that I think are criminally underused: cqi, cqb, cqw, cqh, cqmin, and cqmax. These work like viewport units, but relative to the nearest named container rather than the viewport.

    cqi means “1% of the container’s inline size”. So a heading set to font-size: 5cqi will scale proportionally to its container width. That’s fluid typography without needing a clamp() calculation. It pairs brilliantly with the techniques in fluid typography using CSS clamp(), but for component-scoped scaling rather than viewport-scoped scaling.

    The practical implication: a card component in a narrow sidebar gets proportionally smaller text automatically. The same component in a full-width hero context gets larger text. No extra classes, no JavaScript, no media query override spaghetti.

    Browser support in 2026: the honest picture

    Container queries landed in all major browsers during 2023, but I’d argue real-world adoption in UK production codebases only hit critical mass in 2025. The Can I Use data now shows global support above 93%, and the MDN Web Docs baseline classification moved to “Widely available” in late 2024. For UK-based teams building anything that doesn’t need to support IE11 (which is effectively nobody at this point, and if you’re still supporting IE11 I have questions), container queries are production-safe.

    The one caveat worth mentioning: container-type: size (which establishes containment on both axes) can cause layout issues if you’re not careful about how you’re containing height. The far safer default is container-type: inline-size, which only tracks the horizontal axis. I’ve seen a few UK teams trip over this and spend an afternoon debugging a component that mysteriously collapsed to zero height. Stick to inline-size unless you specifically need both axes.

    Practical patterns for UK design systems

    Let me get specific about where container queries earn their place in a real design system. Three patterns I’d consider non-negotiable:

    Card grids in variable contexts. A product card in an e-commerce listing should look different when it’s one of four across versus one of two. Container queries handle this without any grid-level awareness in the component itself. The component is truly portable.

    Navigation components in sidebars. A lot of UK SaaS dashboards have collapsed sidebars where the navigation needs to switch from labelled icons to icon-only below a certain width. Previously this meant JavaScript, or a media query that broke the component in any non-standard layout. A container query on the sidebar parent solves it cleanly.

    Data widgets in dashboard grids. If you’re building dashboards (and given the amount of UK green tech and fintech products I see coming through, a lot of teams are), a chart or stat widget needs to adapt to its grid cell. This is exactly the use case container queries were designed for. See how this applies to the broader challenges of designing data-dense dashboards that actually work for further context on component adaptability in grid systems.

    What the migration path looks like

    If you’re working in a codebase with existing media query-based responsive components, you don’t have to rewrite everything at once. The sensible approach is to identify components that are already “broken” in non-standard layout contexts, those are your highest-priority candidates. Wrap the component in a container context, migrate the relevant breakpoint rules to @container, test in your grid and sidebar contexts, and delete the media query rules that no longer need to exist.

    Most UK teams I know are running this migration incrementally alongside new feature work rather than as a dedicated refactor sprint. That’s probably the right call. Container queries aren’t a crisis fix; they’re a quality-of-life improvement that compounds over time as more components get migrated.

    The tooling support is also genuinely good now. PostCSS has stable plugins, Stylelint has linting rules for container query syntax, and if you’re using Storybook for your design system, you can set story viewport containers to simulate narrow container contexts. The workflow is mature enough to trust in production.

    If your team is still debating framework choices alongside all of this, the Astro vs Next.js comparison for UK frontend developers is worth a read, since both frameworks handle container query-dependent CSS without friction, but the component model you choose affects how you structure containment contexts.

    Container queries are one of those features that, once you’ve used them properly, make the old way feel genuinely primitive. They don’t replace media queries entirely (viewport-level layout decisions still belong there) but for component-level responsiveness, they’re the right tool. Time to use them.

    Frequently Asked Questions

    What are CSS container queries and how are they different from media queries?

    CSS container queries let a component respond to the size of its parent container rather than the viewport. Media queries fire based on viewport width, which breaks down when the same component is used in different layout contexts like sidebars, modals, and full-width grids. Container queries solve that by making each component genuinely self-aware of its available space.

    Are CSS container queries safe to use in production in 2026?

    Yes. All major browsers including Chrome, Firefox, Safari, and Edge have supported container queries since 2023, and global browser support now sits above 93%. MDN classified them as ‘Widely available’ in late 2024, so for any UK team not supporting legacy browsers, they’re production-ready.

    How do container queries affect the Figma handoff process?

    They encourage designers to create component variants based on container width rather than device breakpoints, which maps directly to @container rules in code. This closes the gap between design intent and implementation, reducing the back-and-forth that typically happens when a component ends up in an unexpected layout context.

    What is container-type: inline-size and should I use it instead of size?

    container-type: inline-size establishes containment only on the horizontal axis, which is the safer default for most UI components. Using container-type: size establishes both axes and can cause elements to collapse to zero height if the container has no explicit height set. Stick to inline-size unless you have a specific reason to track both dimensions.

    Can I use container query units like cqi for fluid typography inside components?

    Yes, and they’re excellent for this. Container query units like cqi work like viewport units but relative to the nearest named container. Setting font-size: 5cqi on a heading means the text scales proportionally to its container width, giving you fluid typography at the component level without needing a clamp() calculation.

  • 3D in the Browser Without Three.js: Using CSS and WebGL Alternatives on UK Client Projects

    3D in the Browser Without Three.js: Using CSS and WebGL Alternatives on UK Client Projects

    Three.js gets all the press. Type “browser 3D tutorial” into any search engine and you’ll wade through pages of Three.js content before anything else surfaces. Which is fine, it’s a genuinely capable library. But on most real UK agency projects, the performance overhead, the bundle size, and the onboarding time for a client’s in-house team make it the wrong call. I’ve watched Three.js get specced into briefs where a handful of CSS 3D transforms would have done the job in two hours and cost nothing in kilobytes. This is a comparison of the lighter approaches: CSS 3D transforms, Spline embeds, and Babylon.js. Browser 3D CSS WebGL alternatives UK agencies can actually ship without a six-week render performance audit afterwards.

    Developer working on browser 3D CSS WebGL alternatives in a UK studio environment
    Photo by MART PRODUCTION on Pexels

    Why the Three.js default is a problem for UK agency work

    The average UK agency project lives and dies by performance budgets that clients don’t fully understand until PageSpeed Insights returns a score in the forties. Three.js minified sits at around 170KB compressed. Add your scene assets, your shaders, your loaders, and you’re routinely looking at 600KB to 1MB of JavaScript before the user has seen a single polygon. On a 4G connection, still the dominant mobile standard for significant chunks of the UK outside major cities, that is a very noticeable wait.

    The Ofcom Connected Nations report consistently shows that rural UK connectivity lags behind headline 5G figures. When you’re building a product site for a client whose audience includes businesses in the Scottish Highlands, rural Wales, or large parts of East Anglia, a 1MB JavaScript payload for a spinning product model is not a sensible trade-off. That’s the first honest conversation most agencies don’t have early enough.

    CSS 3D transforms: genuinely underrated for the right jobs

    CSS 3D transforms are GPU-accelerated, require zero JavaScript dependencies, and have near-universal browser support. The perspective property, transform-style: preserve-3d, and a bit of rotateX/rotateY arithmetic will get you a cube, a card flip, a rotating logo badge, or a parallax depth effect that loads instantly and never blocks the main thread.

    I’d argue the sweet spot is anything that needs to feel three-dimensional without actually being 3D geometry. Navigation menus that flip to reveal content on hover. Hero sections with stacked layers that respond to scroll position via a few lines of vanilla JavaScript. Card components that tilt to follow the cursor. These patterns punch well above their weight visually, and the implementation is something any junior developer can maintain without specialised graphics knowledge.

    The ceiling hits you fast, though. You cannot simulate realistic lighting, you cannot load GLTF assets, and you cannot do physics. Once a client says “I want the product to rotate in 360 degrees with reflections”, CSS 3D is done.

    Spline embeds: the design-tool shortcut with real caveats

    Spline has become a genuinely popular tool in UK product design circles over the last couple of years, and the embed workflow is seductive. A designer builds a scene in the Spline desktop app, publishes it, drops an <iframe> or the Spline viewer script into the page, and it renders. No custom WebGL code. No shader authorship. For design-led agencies where the 3D work lives in the design team rather than the development team, this is a meaningful workflow improvement.

    The catch is the payload. A Spline embed typically loads the Spline runtime (around 300KB compressed) plus your scene file, which varies wildly depending on asset complexity. I’ve seen simple Spline scenes arrive at 800KB total, and complex ones comfortably exceed 2MB. For a hero animation on a landing page where performance is the conversion lever, that’s a hard sell. You’re also handing rendering control to Spline’s infrastructure, if their CDN has a bad moment, your hero goes blank.

    Where Spline earns its place is on pages where the 3D element is supplementary rather than structural: a features section, an “about us” accent, an interactive product teaser behind a scroll trigger. Used like that, with lazy loading in place and a static fallback image for slow connections, it’s a reasonable tool. The key is treating the embed like any other third-party resource: measure it, budget for it, and have a fallback.

    Babylon.js: the serious WebGL alternative most UK devs overlook

    Babylon.js is Microsoft’s open-source WebGL engine, and it’s genuinely impressive. The core engine is around 500KB minified, which is heavier than CSS transforms but lighter than a fully loaded Three.js scene with its ecosystem of add-ons. More relevantly, Babylon’s tree-shaking story is significantly better than Three.js’s: you can import only the modules you need and get meaningful bundle reduction for simpler scenes.

    Where Babylon.js earns serious consideration is the tooling ecosystem. The Babylon.js Inspector is built into the engine and available in development builds, a proper scene graph viewer, material editor, and performance profiler all in the browser. For a UK agency handing a 3D-heavy project to a client’s internal development team after delivery, that is a massive support overhead reduction. “Open the inspector, click the node, change the colour” is a conversation I can have with a non-specialist client. The Three.js equivalent involves editing raw JavaScript.

    Babylon.js also has strong TypeScript support, which matters if your agency has standardised on TypeScript across its frontend stack. The type definitions are maintained by the core team, not a third-party DefinitelyTyped contribution, so they stay current. I’ve found the GLTF loader particularly reliable, less fiddling with material conversion quirks than equivalent Three.js imports from Blender exports.

    The community is smaller than Three.js. Stack Overflow coverage thins out at the edges of the API. But the official documentation is thorough, and the Babylon.js forum is active. For greenfield projects where you’re not borrowing from existing Three.js code, it’s worth the evaluation time.

    How to choose between them on a real brief

    My decision tree is roughly this. If the brief calls for depth and parallax effects, rotating UI components, or card interactions with no actual geometry: CSS 3D, full stop. If the brief calls for a designed scene that a non-coder needs to author and the page is not performance-critical (a marketing splash, a conference landing page, something behind a gate): Spline embed with lazy loading. If the brief calls for real 3D geometry, GLTF assets, physics, or anything a client’s internal team will need to maintain and extend: Babylon.js.

    This maps roughly onto the same thinking behind choosing layout approaches, you wouldn’t use CSS Grid for a simple centred hero any more than you’d use Babylon.js for a card flip. The right tool is the lightest one that does the job. That’s a principle worth holding onto when clients arrive with references to WebGL award sites built by studios with dedicated graphics programmers and no performance requirements.

    A few other things worth noting. WebGPU is arriving properly in 2026, with Babylon.js already shipping a WebGPU backend. That’s going to change the performance ceiling for browser-based 3D significantly over the next couple of years, but it’s still an enhancement rather than a baseline. Plan for it, don’t build for it yet. On the CSS side, container queries are opening up some interesting responsive 3D composition patterns that weren’t feasible eighteen months ago; if you’re doing perspective-based layout work, they’re worth your time. And if you’re already thinking about how text sits in 3D space, the considerations around spatial typography and legibility at depth are directly relevant once you’re placing readable labels inside a three-dimensional scene.

    Performance budgeting for 3D work connects naturally to broader layout decisions. The same discipline that prevents an over-engineered WebGL scene from wrecking a Lighthouse score is the discipline behind structured grid-based layouts that don’t collapse under real-world content. And if you’re building dashboards that incorporate 3D data visualisation, the lessons from designing data-dense dashboards that actually work apply directly, complexity on screen has to justify itself in comprehension, not just in visual ambition.

    Frequently Asked Questions

    What is the lightest way to add 3D effects to a website without a JavaScript library?

    CSS 3D transforms are the lightest option: they use the GPU, require no additional JavaScript, and have full browser support. Using perspective, transform-style: preserve-3d, and rotation values, you can create card flips, parallax depth, and rotating elements with near-zero performance cost.

    Is Spline free to use on client projects?

    Spline has a free tier that allows public embeds, but commercial or private scene hosting requires a paid plan. Check the current Spline pricing page before committing it to a client project, as plan limits around scene exports and team collaboration can affect agency workflows.

    How does Babylon.js compare to Three.js for performance?

    Both engines have similar baseline capabilities, but Babylon.js has better tree-shaking support, meaning you can import only the modules you need and reduce bundle size more reliably. Babylon.js also ships a built-in inspector and stronger TypeScript types, which reduces maintenance overhead on larger projects.

  • Astro vs Next.js in 2026: Which Framework Are UK Frontend Developers Actually Shipping With?

    Astro vs Next.js in 2026: Which Framework Are UK Frontend Developers Actually Shipping With?

    The Astro vs Next.js 2026 debate hasn’t quietened down. If anything, it’s got louder, and for good reason. Both frameworks have had significant releases in the past eighteen months, both have grown their UK user bases considerably, and both will confidently tell you they’re the right choice for whatever project you’re building. They’re not both right. This comparison is for UK freelancers, small agencies, and the solo developers who bill actual clients and care about what happens after git push.

    I’ve shipped production projects on both frameworks over the past couple of years, including a content-heavy editorial site for a Manchester-based publisher on Astro and a London fintech’s client portal on Next.js. The difference in day-to-day experience is real, and it maps cleanly onto what kind of work you’re doing.

    Developer reviewing Astro vs Next.js 2026 code on a laptop at a modern desk
    Photo by Daniil Komov on Pexels

    What each framework actually does

    Next.js is a React meta-framework. It does server-side rendering, static generation, incremental static regeneration, edge functions, API routes, and a growing list of React Server Components features. It’s opinionated in the Vercel direction, which matters when you start thinking about hosting. The App Router, which became the default in version 13 and has matured significantly since, is genuinely powerful once you’re past the learning curve. It’s also genuinely confusing until you are.

    Astro is a different beast. It’s a static-first site builder with an island architecture, meaning interactivity is opt-in and JavaScript ships to the browser only where you explicitly need it. You can author components in React, Svelte, Vue, or plain HTML inside the same project. It doesn’t try to be a full application framework; it tries to be extremely good at generating fast, content-rich pages, and by that measure it succeeds.

    Build performance: where Astro genuinely wins

    Astro’s build times are fast. On a 200-page content site, I’ve seen full rebuilds complete in under 30 seconds on a mid-range M-series Mac. Next.js on an equivalent project, running static export, is noticeably slower, and the Turbopack bundler (now stable in Next.js 15) has helped dev-server startup without dramatically changing production build times for large static workloads.

    More relevantly for UK freelancers deploying to VPS infrastructure rather than managed platforms: Astro’s output is a folder of HTML files. There’s nothing to run. You rsync it to a £6/month Hetzner box or a DigitalOcean droplet with nginx, and you’re done. No Node.js process to keep alive, no PM2 config, no memory creep at 3am. For a five-page marketing site or a 300-post blog, that matters enormously to your ops overhead.

    Next.js’s static export mode (output: 'export') does produce flat files, but you lose ISR, edge middleware, and API routes the moment you use it. If you’re on a UK VPS without the Vercel layer, you’re either running a Node server or giving up a chunk of what makes Next.js compelling. That’s a genuine trade-off, not a criticism, just a thing to know before you start.

    Terminal build output during an Astro vs Next.js 2026 performance comparison
    Photo by Godfrey Atima on Pexels

    Hosting costs on UK infrastructure

    Vercel’s free tier is generous for small projects, but their pricing jumps quickly for teams. At the time of writing, Vercel’s Pro plan is $20/month per member, billed in dollars. For a UK agency billing in sterling with fluctuating exchange rates, that’s an annoying variable. I know several small agencies in the UK who’ve moved Next.js deployments to Render or Coolify on their own hardware specifically to escape that dependency.

    Astro sites on flat hosting are almost embarrassingly cheap. Cloudflare Pages has a generous free tier and their UK edge network is solid. Netlify works fine too. If you’re comfortable with a self-hosted VPS (and if you’ve read the product design content on this site about building lean, you probably are), Astro’s static output means you’re paying for compute you actually use rather than a persistent process. For a busy content site, that’s a real saving over twelve months.

    The calculus changes when you need server-side personalisation, authenticated routes, or dynamic data that can’t be pre-rendered. That’s Next.js territory, and at that point the hosting cost is the cost of the capability, not framework bloat.

    Which project type suits which framework

    I’d pick Astro for: marketing sites, content blogs, documentation sites, portfolio sites, any project where the content is known at build time, any client who doesn’t want to pay for a Node server indefinitely. Astro’s MDX support is excellent, its image optimisation pipeline is genuinely good, and the lack of JavaScript overhead means Core Web Vitals scores that make clients happy. If you’re working on something like a data-heavy editorial layout, the structured grid patterns popular in British editorial design render beautifully in Astro with zero client JS cost.

    I’d pick Next.js for: SaaS products, client dashboards, anything with real-time data, e-commerce with personalisation, applications that need API routes and server-side auth. If you’re building a fintech product that has to comply with FCA requirements and needs server-side session handling, Astro is not the right tool and nobody should pretend otherwise. The React Server Components model in Next.js 15 is genuinely well-suited to complex, data-driven interfaces. The kind of dense, multi-panel dashboards we’ve covered in depth before, for instance data dashboard design for UK government-style tools, need the application-layer features Next.js provides.

    The developer experience gap is closing, but not closed

    Astro 5 introduced server islands and a content layer API that makes it much more capable for hybrid content and dynamic situations. It’s not a full application framework yet, but it’s no longer purely a static tool either. The TypeScript experience in both frameworks is good; Astro’s type inference for content collections is particularly clean, which I find genuinely satisfying in a slightly nerdy way.

    Next.js’s App Router DX still has rough edges. The mental model for caching in Next.js 15 has been reworked (again), and while it’s better, it’s still the part of the framework most likely to produce a support ticket from a confused junior developer on your team. If you’re a solo freelancer who needs to hand a project off to a client’s in-house team of non-specialists, Astro’s conceptual simplicity is an underrated advantage.

    One practical note: if you’re doing any SEO work on behalf of clients, the framework choice affects how you structure pages and metadata. It’s worth checking your on-page implementation against a tool like searchenginetuning.co.uk once you’ve done a build, regardless of which framework you used, since routing differences between the two can create subtle metadata issues that only show up on inspection.

    The honest verdict for 2026

    The framing of “which is better” misses the point. Astro is better for content sites; Next.js is better for applications. The more useful question for UK freelancers is: what’s the default you reach for when a project brief is vague?

    My default is now Astro. Most of the briefs I get are for marketing sites, documentation, or content-led projects where the client doesn’t actually need server-side rendering. Starting with Astro keeps costs low, keeps the architecture simple, and keeps my clients’ Lighthouse scores high. When a project genuinely needs what Next.js offers, I switch without much drama, because the migration path is clear and the use case is obvious by that point.

    The GOV.UK Service Manual guidance on choosing technology has a principle I keep coming back to: choose the simplest thing that meets your needs. For most UK freelance web work in 2026, that’s Astro. For product teams building SaaS, it’s Next.js. Both frameworks are mature, both have futures, and neither is going to embarrass you in a client meeting.

  • Designing for Colour Blindness: What UK Product Teams Get Wrong About Accessible Palettes in 2026

    Designing for Colour Blindness: What UK Product Teams Get Wrong About Accessible Palettes in 2026

    About 1 in 12 men and 1 in 200 women in the UK have some form of colour vision deficiency. That’s roughly 3 million people. And yet, I’d estimate that at least half the digital products I review have UI decisions that make life actively harder for those users. Red-on-green status badges. Light grey placeholder text on white. Gradient buttons where the text disappears on a cheap display. These are not edge cases. They’re just bad colour accessibility design, repeated across the industry at scale.

    The frustrating part is that the tools to catch this have existed for years. WCAG 2.1 has been around since 2018. The Web Content Accessibility Guidelines spell out minimum contrast ratios in plain language. And still, product teams ship inaccessible palettes every single week. Let me walk through why, and what you can actually do about it.

    Designer reviewing colour accessibility design palette on a laptop screen
    Photo by Ron Lach on Pexels

    The WCAG contrast ratios most teams get wrong

    WCAG defines two levels of contrast compliance: Level AA and Level AAA. For normal text, AA requires a contrast ratio of at least 4.5:1. Large text (18pt or 14pt bold) drops to 3:1. AAA pushes normal text to 7:1. Most UK product teams aim for AA, which is reasonable, but they check it once during design handoff and never again after the developer has implemented the palette in code.

    Here’s where it goes wrong. A designer checks the contrast ratio of dark blue text on a white background. Passes. Then a developer applies an opacity value to the same element, or the background becomes a card with a slightly off-white tint, or a hover state changes the background colour. Suddenly you’re at 3.2:1 and nobody’s noticed because nobody re-ran the check. Contrast is not a static property of a colour; it is a relationship between two colours in the exact context they appear.

    I’d also flag that checking contrast ratio alone is not the same as designing for colour vision deficiency. A 4.5:1 ratio between red and green can technically pass a contrast checker while being completely indistinguishable to someone with deuteranopia (the most common form of red-green colour blindness). WCAG compliance and inclusive colour accessibility design are related, but they are not identical.

    The four types of colour vision deficiency you actually need to design for

    Deuteranopia and protanopia are both forms of red-green colour blindness, affecting the green-sensitive and red-sensitive cones respectively. Tritanopia affects blue-yellow perception and is much rarer. Achromatopsia (complete colour blindness) is rarer still. For most practical design decisions, deuteranopia and protanopia are where your palette choices will cause the most problems, and they often produce similar confusion: red, orange, yellow, and green all collapse toward a brownish-yellow or olive spectrum.

    This matters enormously for specific design conventions. Traffic-light status systems (red bad, amber warning, green good) are genuinely problematic for a significant chunk of your users. If your SaaS dashboard uses colour alone to communicate status, you’ve already failed those users, regardless of what your contrast ratio is. The fix is not to abandon colour; it’s to never rely on colour as the only differentiator. Add an icon, a label, a pattern, a shape. Colour should reinforce the signal, not carry it alone.

    Colour swatches showing contrast ratios used in colour accessibility design review
    Photo by Tima Miroshnichenko on Pexels

    Building an accessible colour palette from scratch

    I tend to start palette work in Figma with a base neutral ramp (typically 10 shades from near-white to near-black), then layer in one primary colour and one or two accent colours. The constraint I impose from the start: every interactive element must read clearly when viewed through a deuteranopia simulation, and every text element must pass AA contrast against every background it might appear on.

    A few practical rules I use:

    Avoid pure red and pure green as paired status indicators. If you need two semantic colours for success and error states, try blue and orange, or blue and red. Blue is safe for almost all colour vision deficiencies. If your brand insists on green for success, pair it with a distinct shape or icon, not just a colour change.

    Increase contrast beyond the minimum. 4.5:1 is the floor, not the target. I aim for 6:1 on body text as a working default. On interactive elements like buttons and form inputs, I want the border or outline to carry contrast independent of fill colour, so the element’s boundaries are clear even if the fill reads as a similar hue to the background for some users.

    Test your palette in a simulator, not just your head. Figma has a built-in colour blindness simulator under View > Accessibility. Sketch and Adobe XD have similar options. I also regularly paste screenshots into Coblis or the browser extension Colorblindly to see how a full page reads. This is not optional. Your own colour perception is not a reliable test instrument.

    Check states, not just default views. Hover states, focus rings, disabled states, error states, selected rows in a table. Each of these introduces a new colour context that needs its own accessibility check. This is where I see empty state UI design go wrong too: teams design the happy path accessibly and forget the edges.

    Where UK product teams specifically trip up

    The Government Digital Service accessibility guidelines are genuinely excellent, and GOV.UK itself is one of the better-performing large sites on colour accessibility. The problem is that outside of public sector work, most UK product teams treat accessibility as a compliance checkbox rather than a design constraint that applies from day one.

    I see three recurring failure modes. First: palette inherited from a brand identity created by a print agency, where colour choices were made for CMYK output with no thought given to screen contrast. The brand colour is a soft teal on white, it looks lovely on a business card, and it reads at 2.8:1 on screen. Second: a dark mode implementation added after launch that nobody tested with a contrast tool at all. Third: teams that do check WCAG but only check the primary brand blue on white, then assume the rest of the palette is fine.

    If your team is shipping anything that touches the public (and especially if it handles data, finance, or health information), you also have legal considerations. The Public Sector Bodies (Websites and Mobile Applications) Accessibility Regulations 2018 require WCAG 2.1 AA compliance for public sector bodies. Private sector products are not yet legally mandated in the same way, but the UK government’s accessibility guidance is worth reading regardless of whether you’re building for the public sector, because it’s simply well-written practical advice.

    For teams checking deliverability and technical health across their digital stack, tools like dijitul can surface issues that are easy to miss when you’re deep in the product work itself.

    The semantic colour system approach

    The most resilient approach I’ve seen for colour accessibility design is building a semantic token layer on top of your raw palette. Instead of using hex values directly in components, you reference tokens like --color-status-error, --color-interactive-primary, --color-text-muted. The token values can change for dark mode or high-contrast mode without the component needing to know anything about it.

    This is also where the data dashboard UI design work gets genuinely interesting: when your chart colours are semantic tokens, you can ship a colour-blind-friendly palette mode as a user preference with very little engineering effort. ONS and DEFRA both use this kind of approach in their public data tools, and it’s something more UK product teams should be borrowing.

    The other thing I’d push for is putting contrast ratio checks into your CI pipeline, not just your design review. Tools like AI-assisted code review can catch some accessibility regressions, but a dedicated linter like axe-core or pa11y will catch colour contrast failures at the component level automatically. Shift left. Find it before the release, not in a user complaint six months after.

    Quick wins for teams starting from an inaccessible baseline

    If you’re inheriting an existing product with a broken palette, you don’t always get to start from scratch. The quickest wins: darken your primary text colour (near-black, not pure black, ideally around #1a1a1a on white gives you headroom), lighten your backgrounds to true white or near-white, and add visible borders to all form inputs. Those three changes alone will fix a significant portion of contrast failures without touching your brand colours.

    For semantic status colours, swap to filled badges with white text instead of coloured text on white backgrounds. A red badge with white text reads at roughly 5.5:1 for standard red; red text on white is usually around 3.9:1. Same brand colour, meaningfully better contrast.

    Colour accessibility design is not a niche concern, and it’s definitely not a “nice to have” for UK teams building products in 2026. It’s just good design. The users who benefit most from an accessible palette are rarely the ones who make the most noise about it, which is exactly why product teams keep getting it wrong.

    Frequently Asked Questions

    What contrast ratio do I need to pass WCAG 2.1 AA for normal text?

    Normal body text needs a contrast ratio of at least 4.5:1 between the text colour and background colour. Large text (18pt regular or 14pt bold) only requires 3:1. You can check ratios using free tools like the WebAIM Contrast Checker.

    Does passing a contrast ratio check mean my design is colour blind friendly?

    Not automatically. A contrast ratio check measures luminance difference, not hue distinction. Red and green can have a technically passing contrast ratio while being completely indistinguishable to someone with deuteranopia. Colour vision deficiency testing requires a separate simulation tool on top of contrast checking.

    What is the most common type of colour blindness I should design for?

    Deuteranopia (reduced green cone sensitivity) and protanopia (reduced red cone sensitivity) together affect roughly 8% of men in the UK. Both cause difficulty distinguishing reds, greens, and related hues. Designing for these two covers the vast majority of users with colour vision deficiency.

    Are UK websites legally required to meet colour accessibility standards?

    Public sector websites and apps are legally required to meet WCAG 2.1 AA under the Public Sector Bodies Accessibility Regulations 2018. Private sector products are not currently subject to the same legislation, but accessibility failures can still create liability under the Equality Act 2010 if disabled users are disadvantaged.

  • Designing Cookie Consent Flows That Don’t Destroy Your Conversion Rate: A UK PECR and ICO Compliance Guide

    Designing Cookie Consent Flows That Don’t Destroy Your Conversion Rate: A UK PECR and ICO Compliance Guide

    Here is the uncomfortable truth about most cookie banners: they were designed by lawyers, not designers. You can tell. They sit there like a passive-aggressive sticky note, blocking your content, hiding the reject button in a font size that would strain the eyes of someone half my age, and generally making a first impression that screams “we don’t actually want you to say no.” That is not just aesthetically grim, it is increasingly illegal. The ICO’s 2024 enforcement push against non-compliant consent mechanisms made clear that cookie consent UI design UK ICO PECR compliance is not a technicality you can paper over with a barely-visible opt-out link.

    This piece goes through what PECR actually demands, what the ICO’s published guidance says about interface design specifically, and how to build a consent flow that is both genuinely compliant and not a conversion catastrophe. Because those two things are not mutually exclusive, they just require some actual design thinking.

    Clean cookie consent UI design showing equal-weight accept and reject buttons for UK ICO PECR compliance
    Photo by Pixabay on Pexels

    What PECR actually requires (without the legalese)

    The Privacy and Electronic Communications Regulations 2003, PECR, sit alongside the UK GDPR and are enforced by the ICO. For cookies specifically, PECR requires prior, informed, freely given consent before any non-strictly-necessary cookie is set. That is the short version. The full version has some sharp teeth.

    “Freely given” is where most implementations fail. If you pre-tick boxes, if accepting is one click but rejecting requires three, if you grey out the reject button or bury it in a “Manage preferences” submenu that takes six taps to navigate, that is not freely given consent. The ICO has been explicit: consent obtained through designs that nudge users towards acceptance does not meet the standard. They call these dark patterns, and they have published specific examples of what counts as one.

    Strictly necessary cookies, those needed to make the site function, like session cookies, do not need consent at all. Everything else does. Analytics, advertising pixels, A/B testing scripts, heat-mapping tools, embedded YouTube players: all of these require prior opt-in unless you are routing them through a proxy that strips identifiers. That last option is genuinely worth exploring if analytics are your only concern, but it is out of scope here.

    The dark patterns the ICO specifically flags

    I would recommend reading the ICO’s updated cookie guidance directly, because it is more specific than most designers expect. The patterns they name include:

    Asymmetric prominence. The “accept all” button is large, colourful, and high-contrast. The “reject” or “manage” option is smaller, greyed out, or styled as a text link. This visual hierarchy communicates a preference, which means consent is not freely given.

    Forced interaction. Making users click through multiple screens to reject, whilst acceptance is one button. If it takes three steps to say no and one step to say yes, you have built a funnel, not a consent flow.

    Confusing language. “Allow partners to use personalised data” is not informed consent. People need to understand what they are agreeing to. Plain English is not optional.

    Consent walls. Blocking content access unless the user accepts all cookies. The ICO’s position is that this can undermine the “freely given” requirement, particularly where genuine alternatives to the service do not exist.

    UI patterns that work without being ugly

    The good news is that compliant does not mean clunky. Here is how I would build this.

    Symmetric button styling

    Give “Accept all” and “Reject all” equal visual weight. Same button size, same border treatment, same font weight. The only permissible difference is colour, and even then, use brand colours rather than a bright green accept versus a faded grey reject. Monochrome button pairs work particularly well: both buttons outlined, no fill, identical typography. Clean, considered, legally sound.

    Three-option layouts

    The most practical pattern for most UK product teams is a three-button row: “Reject all”, “Manage preferences”, “Accept all”. This gives users the quick binary choice if they want it, whilst making granular control available without friction. Put “Reject all” on the left, counterintuitive, but it signals confidence rather than reluctance. Users who are privacy-conscious will find it immediately; users who genuinely want to accept everything will still accept.

    The modal vs banner question

    Banners (bottom or top strips) tend to generate higher interaction rates but lower comprehension. Modals with a backdrop generate better-informed choices but disrupt flow more severely. For most sites, a centre-screen modal on first visit is the right call, it signals that the choice matters without being dismissive. Avoid full-screen takeovers; they are aggressive and associate your brand with the very dark patterns you are trying to avoid.

    Preference panels worth building

    The preference panel (reached via “Manage preferences”) is where most implementations fall apart. I have seen panels that list seventeen toggle switches with descriptions like “Audience measurement partner 4”, completely useless to an ordinary person. Build category-level toggles: Analytics, Marketing, Personalisation. Describe each in one sentence of plain English. Show which third parties are involved, but summarise rather than enumerate. Make the panel closeable without forcing a decision, some users just want to read before choosing.

    If you are building this in a component library, the preference panel is a good candidate for a compound component pattern: a top-level ConsentPanel that takes category configs as props, renders toggle groups with associated descriptions, and emits a structured consent object that your tag manager or consent management platform can consume. Keep the state management simple, a flat object keyed by category slug is all you need.

    Colour, contrast and accessibility

    This connects to accessibility work more broadly. If you have been following guidance on designing for older users and accessibility for the over-55 audience, most of it applies directly here. Consent flows need to meet WCAG 2.2 AA contrast ratios; the ICO’s own published guidance references accessibility standards. Minimum 4.5:1 for body text, 3:1 for large text. Focus states on all interactive elements. No relying on colour alone to distinguish accept from reject.

    Typography matters here too. Do not use a font size below 14px in a consent banner. Sixteen is more defensible. If you have been thinking carefully about your typography stack and system fonts, a consent modal is a good place to use a system font stack, it loads instantly, which matters given that consent must be presented before non-essential scripts fire.

    Technical implementation notes

    A few things I see trip up developers who are building consent flows from scratch rather than using a consent management platform (CMP).

    First, no cookies should be set before consent is given. This sounds obvious but is violated constantly. If your analytics script fires on page load regardless of consent state, you are non-compliant before the banner has even rendered. Consent must gate script execution, not just set a preference that is read later.

    Second, consent must be recorded and reproducible. You need to store what the user consented to, when, and which version of your policy was active at the time. A UUID per consent event, stored server-side, is the clean solution. Storing consent state only in a cookie is weakly circular and difficult to audit.

    Third, consent must be withdrawable as easily as it was given. If your site has a footer link labelled “Cookie settings” that opens your preference panel, which was the mechanism for giving consent, that satisfies this requirement neatly. Make sure it actually works, and make sure it re-presents the panel with the current state rather than defaulting to all-off.

    If you are building empty states into your consent flow (think: the preference panel before any categories have been toggled), there is a nice pattern for communicating status clearly covered in the piece on designing effective empty states for UK SaaS onboarding, the principle of communicating what will happen next applies well here.

    Does any of this actually hurt conversion?

    The honest answer is: a well-designed compliant consent flow will reduce your analytics data compared to a dark-pattern banner that coerces acceptance. That data was always unreliable anyway, because coerced consent produces noise rather than signal, people who clicked accept reflexively are not the engaged users your analytics should be modelling.

    What it will not do is hurt your conversion rate in the sales funnel sense, provided the consent flow does not block content access. A modal that appears, presents a genuine choice, and dismisses cleanly adds perhaps two seconds to a user’s first visit. That is negligible against the reputational and legal cost of an ICO enforcement notice, which can run to fines of up to £500,000 under PECR, or higher under the UK GDPR framework that sits alongside it.

    Build the consent flow as a real UI component, not an afterthought. Treat it with the same design rigour you would give a checkout flow or an onboarding sequence. That is the entire argument.

    Frequently Asked Questions

    What does PECR require for cookie consent in the UK?

    PECR requires that you obtain prior, informed, and freely given consent before setting any non-strictly-necessary cookies. This means no pre-ticked boxes, no dark patterns that push users towards acceptance, and the ability to withdraw consent as easily as it was given. Strictly necessary cookies, session management, shopping baskets, are exempt.

    Is a cookie banner enough to be ICO-compliant, or do I need a full consent management platform?

    A banner alone is not sufficient; what matters is that non-essential scripts are genuinely blocked until consent is given, that preferences are recorded with a timestamp, and that users can change their choice later. A consent management platform (CMP) handles most of this, but you can build a compliant system from scratch if you implement the technical requirements correctly. The ICO does not mandate any specific tooling.

    Are dark patterns in cookie consent actually enforced in the UK?

    Yes. The ICO issued enforcement notices against major UK publishers in 2024 specifically citing non-compliant consent interfaces, including asymmetric button styling and buried reject options. Fines under PECR can reach £500,000, and the ICO has stated publicly that enforcement in this area is ongoing.

    Can I style my accept button differently from the reject button?

    Using different colours is acceptable provided there is no significant difference in prominence, size, font weight, and placement should be equal. The ICO’s guidance specifically flags making the reject option visually subordinate as a dark pattern. Monochrome, equal-weight button pairs are the safest approach.

    Does a cookie consent modal affect page load performance or Core Web Vitals?

    It can, but the impact is manageable. Using a system font stack in your consent modal avoids any additional font-loading overhead. The modal itself should be lightweight HTML and CSS, ideally inlined, so it renders before external scripts fire. Blocking non-essential third-party scripts until consent is given can actually improve your initial load performance, as those scripts are often the heaviest assets on the page.

  • How to Design Effective Empty States: The UI Pattern UK SaaS Products Consistently Underestimate

    How to Design Effective Empty States: The UI Pattern UK SaaS Products Consistently Underestimate

    Empty states are the screens nobody designs until the last sprint. You know the ones: the blank table with no rows, the notification panel with nothing in it, the inbox on day one. Most UK SaaS products treat these moments as edge cases. I’d argue they’re some of the most consequential screens in your entire product, and getting them wrong is quietly killing your activation rates.

    The idea behind empty state UI design is simple enough. When a user has no data, no content, and no history in a given context, what do they see? If the answer is a white box and a sad little grey sentence reading “No items found”, you’ve essentially handed a new customer a locked room and no key.

    Smartphone displaying an empty state UI design example relevant to SaaS UK product teams
    Photo by Tima Miroshnichenko on Pexels

    Why empty states matter more than your onboarding flow

    There’s a tendency in UK SaaS product teams to spend weeks on the formal onboarding wizard, complete with progress bars and illustrated walkthroughs, and then dump the user into an empty dashboard with zero guidance. The problem is that onboarding ends. Empty states don’t. A user who creates a new project, a new workspace, a new report, or a new team will hit an empty state every single time they do something new. That’s not an edge case; it’s a recurring event across the entire user lifecycle.

    Slack does this brilliantly. Every new channel you create opens with a short message explaining the channel’s purpose and what a first message might look like. It costs almost nothing to implement and transforms what would be a void into a prompt. Notion does something similar with placeholder text in empty databases. These aren’t accidents; they’re the result of product teams treating empty states as part of the core UX, not an afterthought.

    The three types of empty state and how to handle each one

    Not all empty states are the same, and designing a single generic treatment for all of them is a mistake. I tend to split them into three categories.

    First-use empty states appear when someone uses a feature for the first time and has no data yet. This is prime onboarding real estate. The design should explain what the feature does, show the user what the filled state will look like (even if just as an illustration), and give them a single, clear call to action. One button. Not three. The copy should be active and encouraging without being patronising.

    No-results empty states happen after a search or filter returns nothing. These are different because the user has intent. They were looking for something specific. The design here should acknowledge what they searched for, suggest alternatives (fix the filter, broaden the search, check the spelling), and avoid making the user feel like they’ve hit a wall. If your product is a UK-facing B2B tool and someone searches for an invoice that doesn’t exist, the worst possible response is just “No results”.

    Cleared or completion states occur when a user has genuinely finished something: an empty inbox, a completed task list, a fully processed queue. These deserve a moment of positive reinforcement. Something brief that says “you’re done” works better than the same blank void that appears everywhere else. The tone should feel different to the first-use state, because the context is totally different.

    Copy is doing 70% of the work

    Most empty state design discussions focus heavily on the illustration. And look, a well-crafted illustration helps. But I’ve reviewed products where a decent illustration sat above catastrophically bad copy, and the screens were still useless. The copy is doing most of the heavy lifting.

    A few principles I come back to repeatedly. First: lead with what the feature does, not with what’s missing. “You haven’t added any team members yet” is worse than “Invite your team to start collaborating on projects.” One focuses on absence; the other focuses on possibility. Second: keep the call to action on the screen and make it obvious. Users who hit a blank state shouldn’t have to navigate somewhere else to fix it. If the empty state is a contacts list, there should be an “Add contact” button right there on the screen. Third: match the tone of your product voice. A fintech product aimed at UK accountants shouldn’t suddenly go whimsical with a cartoon dog in the empty state. Consistency matters.

    The GOV.UK Service Manual has good underlying principles about clarity and plain language that translate usefully into SaaS copy, even if the style is obviously different. The core idea, that users shouldn’t need to think hard about what to do next, applies everywhere.

    Illustrations: useful tool or distraction?

    The illustrated empty state became almost universal in SaaS products around 2019 and I’ve watched it calcify into a cliché. Teams reach for an undraw.co illustration, drop it above a heading and a button, and call it done. That’s not necessarily wrong, but it’s rarely right either.

    An illustration earns its place when it genuinely communicates something: the nature of the feature, what the filled state might contain, or a sense of scale. It doesn’t earn its place when it’s decorative filler that adds loading weight without adding meaning. For mobile especially, an oversized illustration that pushes the call to action below the fold is doing active harm.

    If you’re working on a product that needs to feel serious, like a compliance tool, a legal SaaS, or anything facing UK regulated industries, an illustrated empty state can actually undermine trust. A clean typographic treatment with precise copy often performs better than anything illustrated. Test it. Don’t assume.

    Empty states in dashboards: the hardest case

    Dashboard empty states are particularly awkward because dashboards are often module-based. You might have eight widgets and only three have data yet. The result is a patchy grid of partially populated information and multiple empty modules, each with their own small sad state. This fragments the experience badly.

    There’s a strong argument for using a progressive disclosure approach here: show only the modules the user has data for, surface the others as locked or greyed-out with a prompt to set them up. This is the approach I’ve seen work well in UK SaaS products that handle analytics or project management. It’s related to a broader point about structured layout thinking; the article on why British editorial and SaaS sites are returning to structured grid layouts has some useful thinking about how composition affects perceived completeness.

    For data-heavy dashboards specifically, there’s real value in pre-populating with sample data. Show the user what their dashboard could look like with placeholder numbers, labelled clearly as sample data, so they understand the value proposition before they’ve put any real information in. Notion does a version of this with their templates. It’s honest, it’s useful, and it turns what would be a confusing blank grid into an immediate demonstration of product value. More on designing those kinds of interfaces in the piece on designing data-dense dashboards that actually work.

    Testing your empty states properly

    Most teams test empty states by manually clearing their test account and looking at the screen. That’s better than nothing. But the real test is watching a real new user hit an empty state for the first time and seeing what they do. Do they understand what the feature is for? Do they know what to do next? Do they feel lost or do they feel guided?

    User testing sessions with participants who are genuinely unfamiliar with the product are invaluable here. If your team is based in the UK and doing any kind of remote testing through tools like Maze or UserTesting, recruit participants who match your actual user profile, not just whoever is convenient. You’ll learn things from a 45-year-old accountant in Birmingham navigating your empty transaction list that you’d never catch internally.

    Typography also matters on these screens more than people expect. A well-chosen typeface with the right weight and spacing can make empty state copy feel considered rather than thrown together. If you’re still using system defaults without thinking about hierarchy, the piece on building a proper typography stack in 2026 is worth your time.

    The bottom line is that empty states are not maintenance work. They’re product design work. Every time a UK SaaS product ships a blank white screen with two words of placeholder text, it’s leaving activation, retention, and trust on the table. The fix isn’t expensive. It’s just attention, and a bit of craft applied to the moments most teams skip.