Topic 25.9
Cross-Cutting Concerns: Performance, Accessibility, i18n and Security at Design Time
In one line
Some requirements touch every screen: performance budgets tied to Core Web Vitals, accessibility to WCAG 2.2 AA, localisation for many languages and directions, security boundaries (XSS, CSP, auth), and observability; deciding them at design time is cheap, retrofitting them is not, so bring the same checklist to every design.
Think of it like this
Building a school. Ramps for wheelchairs, fire exits, signs in two languages and a guard at the gate are planned on the drawing, before the walls go up. Adding a ramp after the steps are poured means breaking concrete. Performance, accessibility, languages, security and monitoring are the ramps and fire exits of a frontend: they cut across every room, so they go into the design.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- Core Web Vitals
- Three speed measures from real visits: LCP (main content shows), INP (response to input) and CLS (layout jumping).
- 75th percentile (p75)
- The value 75% of visits are better than. Budgets use it so most users, not just the fastest, get a good experience.
- WCAG 2.2 AA
- The usual accessibility target: a published set of testable rules at the middle (AA) level.
- i18n / l10n
- Internationalisation (making an app translatable) and localisation (actually adapting it for a language and region).
- Logical properties
- CSS like
margin-inline-startthat follows the reading direction, so layouts flip correctly for right-to-left languages. - XSS
- Cross-site scripting: an attacker's script running inside your page. React's escaping prevents most of it.
- CSP
- Content Security Policy: a response header that tells the browser which scripts and resources may load.
- Observability
- Being able to see how the app behaves for real users: metrics, errors, logs, traces and alerts.
Step by step
01Put numbers on performance
Write the budget next to the requirements: LCP ≤ 2.5 s, INP ≤ 200 ms, CLS ≤ 0.1 at p75 on mobile, plus resource limits per route. Then name the design choices that keep you inside it.
{
"route": "/feed",
"p75": { "lcpMs": 2500, "inpMs": 200, "cls": 0.1 },
"resources": { "jsKbGzip": 170, "cssKbGzip": 30, "lcpImageKb": 100, "fonts": 2, "thirdPartyScripts": 1 }
}02Name the accessibility requirements
Target WCAG 2.2 AA and list the patterns your design uses (combobox, dialog, feed, grid), how focus moves on navigation and in dialogs, what gets announced, and how charts and images are described. Put the hard parts into design-system components.
03Plan for many languages
Messages in catalogues with plurals, Intl for numbers and dates, logical CSS properties and dir, locale in the URL, translations split per locale. The live example shows how much formatting changes between locales.
04Draw the trust boundaries
Everything in the browser can be read and changed by the user, so the boundary is the server. Draw it on the architecture diagram and list what crosses it.
05Plan observability and the rollout
List the metrics (Core Web Vitals per route, error rate, API latency, the feature's success metric), the alerts and the dashboards. Ship behind a feature flag, compare metrics between flag on and off, and keep a rollback plan.
06Run the checklist
At the end of a design, go through the checklist in the code below. It takes two minutes and catches the gaps interviewers and reviewers look for.
Try it yourself
- 1
Fix a route on paper, then in data
In the budget example, decide which design changes would bring
/product/42under budget, then change its numbers to what you expect after the fix. Predict the console line first. - 2
Count in Arabic
In the locale example, switch to
ar-EGand click +1 several times. Arabic has six plural categories; predict which message appears for 2, then for 3 and for 11. Check by addingconsole.log(new Intl.PluralRules("ar-EG").select(11)). - 3
Break the layout with physical properties
Change
padding-inline-startandborder-inline-starttopadding-leftandborder-left. Switch toar-EG. What looks wrong, and why do logical properties fix it?
Code & diagrams
Each failure points to a design fix: `/product/42` needs a smaller, prioritised hero image with reserved space (LCP and CLS); `/dashboard` needs code splitting and transitions for heavy chart updates (JS and INP). The result is text plus colour, never colour alone.
Preview
Console
Nothing logged yet.Expected console output
/feed: pass
/product/42: FAIL lcpMs 3100 > 2500, cls 0.18 > 0.1, lcpImageKb 240 > 100
/dashboard: FAIL inpMs 260 > 200, jsKb 210 > 170Plural rules, digits, grouping, currency position, date order and "yesterday" all change with the locale, and none of it is hand-written. Switch to `ar-EG`: the layout flips because of `dir="rtl"`, and the blue bar moves to the right because the CSS uses logical properties.
Preview
Console
Nothing logged yet.Expected console output
en-IN | 3 items in your cart | ₹12,34,567.50 | 15 Jan 2024 | yesterday
de-DE | 3 Artikel im Warenkorb | 1.234.567,50 ₹ | 15.01.2024 | gestern
ar-EG | ٣ منتجات في السلة | ١٬٢٣٤٬٥٦٧٫٥٠ ₹ | ١٥/٠١/٢٠٢٤ | أمس## Requirements
- [ ] Functional requirements and what is out of scope
- [ ] Numbers: users, items per page, data sizes, freshness, concurrency
- [ ] Devices and networks to budget for (e.g. mid-range phone, 4G)
## Architecture
- [ ] Rendering per route (CSR / SSR / SSG / ISR / streaming / RSC) and why
- [ ] Component tree for the main screen
- [ ] Every piece of state labelled: server cache, URL, client store, local, form
- [ ] API layer: auth, timeouts, safe retries, errors, de-duplication
- [ ] Loading and error regions (Suspense + error boundaries), empty states
## Data model and interface
- [ ] Client types, normalised entities, ids (client ids for optimistic creates)
- [ ] Endpoints/messages with shapes, pagination cursors, real-time events, idempotency
## Performance
- [ ] Budgets: LCP <= 2.5 s, INP <= 200 ms, CLS <= 0.1 at p75; JS KB per route
- [ ] Code splitting, image sizing and priority, virtualisation, caching, prefetching
## Accessibility (WCAG 2.2 AA)
- [ ] Semantic HTML, keyboard paths, focus management, ARIA patterns used
- [ ] Live announcements, contrast, target size, reduced motion, text alternatives
## Internationalisation
- [ ] Message catalogues with plurals, Intl formatting, RTL with logical CSS
- [ ] Locale in URL, translations split per locale, long-text layouts
## Security
- [ ] No unsanitised HTML, safe URLs, CSP, HttpOnly cookies, CSRF
- [ ] Authorisation on the server for every read and write; secrets never in the bundle
- [ ] Third-party scripts listed and kept off sensitive pages
## Observability and rollout
- [ ] RUM per route, error reporting with source maps, traces, success metric
- [ ] Alerts, dashboards, feature flag, rollback planBreak it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Build sentences by joining strings
In the locale example, replace the plural lookup with const msg = n + " items in your cart"; and run it.
Myth vs fact
Myth
Performance, accessibility and i18n can be added after launch.
Fact
They can, at many times the cost: retrofitting focus management, RTL layouts or server rendering touches every screen. Deciding them in the design is cheap.
Myth
A good Lighthouse score means real users have a fast site.
Fact
Lighthouse is a lab test on one machine. Core Web Vitals are judged on real users at p75, on their devices and networks; you need RUM to know.
Myth
React prevents all XSS.
Fact
React escapes text, but dangerouslySetInnerHTML, javascript: URLs, injected third-party scripts and server-rendered data in inline scripts can still open holes. CSP and code review cover what escaping doesn't.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
INP replaced FID (First Input Delay) as a Core Web Vital in March 2024. INP looks at all interactions on a page, not just the first, which is why long tasks during the whole session, such as heavy re-renders, now matter for the score.
- ▸
Budget per route and per device class: a dashboard used on desktops by staff and a product page used on phones by the public deserve different limits. A single global budget is either too loose or blocks the wrong teams.
- ▸
Intldata comes with the browser, so formatting adds nothing to your bundle; message catalogues and ICU parsing do. Precompiling messages at build time and splitting them per route keeps i18n cheap. - ▸
In design reviews, ask "how will we know this is broken?" for each feature. If the answer is "a user tells support", the observability section is missing.
Remember this
- 1
Performance budgets and Core Web Vitals. Core Web Vitals are Google's user-centred speed metrics, measured at the 75th percentile of real visits: LCP (Largest Contentful Paint, when the main content appears) good at ≤ 2.5 s; INP (Interaction to Next Paint, how fast the page responds to taps and keys) good at ≤ 200 ms; CLS (Cumulative Layout Shift, how much things jump) good at ≤ 0.1 (Phase 23.4). A performance budget turns them into limits the team checks automatically: for example "initial JavaScript ≤ 170 KB gzipped per route, LCP image ≤ 100 KB, no more than 2 web fonts". Design choices that serve the budget: server rendering or static generation for content pages, route-level code splitting, images with reserved sizes, virtualised long lists, keeping urgent updates fast with transitions, and third-party scripts loaded late or not at all.
- 2
Accessibility requirements. State the target: WCAG 2.2 level AA. In a design that means: semantic HTML first (real buttons, links, headings, landmarks, labels, Phase 18.1); every interaction works by keyboard with visible focus and a sensible focus order; focus is managed on route changes, dialogs and dynamic content (Phase 18.2); custom widgets follow ARIA patterns (combobox, dialog, tabs, feed, grid, Phase 18.3–18.4); dynamic updates are announced through live regions; colour contrast is at least 4.5:1 for text; targets are at least 24×24 CSS px (WCAG 2.2); motion respects
prefers-reduced-motion; charts and images have text alternatives. Build these into the design system so every team inherits them, and test with axe in CI plus a real screen reader before launch (Phase 18.5). - 3
Localisation (i18n). Internationalisation (i18n) means building the app so it can be translated and adapted; localisation (l10n) is doing it for each locale (Phase 22.5). Design decisions: no text in code (messages in catalogues with ICU plurals, because "1 item / 2 items" rules differ by language); numbers, currencies, dates and relative times formatted with the built-in
IntlAPIs; right-to-left languages (Arabic, Hebrew) handled withdir="rtl"and CSS logical properties (margin-inline-startinstead ofmargin-left); layouts that survive text 30–50% longer than English; locale in the URL (/de/...) for SEO withhreflanglinks; and translations loaded per locale as separate chunks so nobody downloads all languages. - 4
Security boundaries. Write down where trust ends. XSS (cross-site scripting, running an attacker's script in your page) is prevented by React escaping text by default; the design forbids
dangerouslySetInnerHTMLexcept through a sanitiser (Phase 21.1–21.2) and validates URLs (javascript:links, Phase 21.3). A Content Security Policy (CSP), an HTTP header listing which scripts may run (with nonces for inline scripts), limits damage if something slips through (Phase 21.6). Auth: session tokens inHttpOnly,Secure,SameSitecookies rather thanlocalStorage, CSRF protection for cookie-authenticated writes, and every authorisation decision on the server: the client only hides what the user can't use (Phase 21.4–21.5). Payments use the provider's hosted fields (Topic 25.6). Third-party scripts are a supply-chain risk: list them, load them late, and keep them off sensitive pages. - 5
Observability. If you can't see it, you can't keep it working. Plan RUM for Core Web Vitals per route and device class, error reporting with source maps and release tags (Phase 23.5), logs and traces that connect a frontend request to backend spans (a trace id header), product analytics for the feature's success metric, and alerts on regressions (error rate up after a release, LCP p75 over budget). A design doc should list the metrics, their targets, the dashboards and who gets paged.
- 6
The checklist habit. Every design in this phase ended with the same questions: is it fast (budgets), usable by everyone (a11y), ready for other languages (i18n), safe (trust boundaries) and observable (metrics and alerts)? Saying them in the last ten minutes of an interview shows seniority; writing them into a design doc prevents expensive fixes. The checklist at the end of this topic is meant to be copied.
Explain it without notes
What are Core Web Vitals, their "good" thresholds, and how do they shape a frontend design?
Which accessibility requirements would you write into a frontend design?
How do you prepare a React app for many languages, including right-to-left?
Where are the security boundaries in a React frontend, and what do you put in the design doc?
What would you monitor after launching a new frontend feature?
Practice
Add a fonts limit of 2 to the budget example and a fonts value for each route; make /feed use 3 fonts.
Add hi-IN (Hindi) to the locale example with English-like plural forms, and check how the price is formatted.
Trade-offs
- ↔
Strict budgets keep the product fast but slow down feature work and need tooling; start with budgets on the few routes that matter most (landing, product, checkout) and widen later.
- ↔
A full i18n setup from day one costs time even if you launch in one language; at minimum keep text out of components and use
Intl, which makes translation cheap later. - ↔
A strict CSP blocks many attacks but breaks third-party widgets and inline scripts until they're refactored; roll it out in report-only mode first.
Done when you can
I can state Core Web Vitals targets and turn them into per-route budgets.
I can list the accessibility requirements of a design, with the ARIA patterns it needs.
I can design for localisation: catalogues, plurals, Intl, RTL and logical CSS.
I can draw the security boundary and list XSS, CSP and auth decisions.
I can plan observability: RUM, errors, traces, success metrics and alerts.
I can run the frontend design checklist at the end of any design.