How do you ensure a11y, i18n, and responsive design in Svelte?
Svelte Developer
answer
I design Svelte components with a11y-first semantics, keyboard support, and ARIA only when native roles are insufficient. I add internationalization (messages, dates, plurals, RTL) via keyed dictionaries and formatters, avoiding concatenation. For responsive design, I use fluid layout tokens, container queries, and adaptive rendering. I enforce maintainable code with props contracts, slots, stores, typed actions, comprehensive tests, and linting that checks a11y, i18n coverage, and CSS constraints.
Long Answer
Svelte encourages small, composable components, which makes it ideal for building experiences that are accessible, internationalized, and responsive without bloated abstractions. My approach is to treat these three concerns as first-class architecture requirements rather than late-stage add-ons. The goal is predictable UX across input methods and viewports, correct language and locale behavior, and a codebase that the team can evolve safely.
1) Accessibility foundations
I start with semantic HTML: buttons are <button>, links are <a>, headings follow a logical outline, and form controls use <label for> with properly associated inputs. I avoid ARIA where native semantics suffice, and apply ARIA roles or aria-* only to fill semantic gaps (e.g., role="dialog" with aria-modal="true"). Interactive elements implement keyboard navigation (Tab, Shift+Tab, Arrow keys where applicable) and focus management (roving tabindex, focus trap for modals, return focus on close). Visually hidden text uses a utility class instead of display:none to keep it available to assistive tech. For media and motion, I respect prefers-reduced-motion and supply captions/alt text. Error messaging is linked to controls with aria-describedby, and live updates use aria-live="polite" regions. I test with screen readers and include unit/UI tests for focus ordering and keyboard behavior.
2) Accessibility in Svelte specifics
Svelte’s actions and bindings are perfect for a11y utilities. I encapsulate focus trapping as an action (use:focusTrap), inert background handling, Escape to close, and outside-click detection without leaking event listeners. I prefer slots for labeling: the parent can pass <slot name="label"> or an aria-label prop—never hardcoding visible text inside the component. For form fields, I export a compound component pattern: <Field.Root>, <Field.Label>, <Field.Input>, <Field.Hint>, where the root wires up IDs and relationships automatically. Linting is enforced with eslint-plugin-svelte and a11y rules to catch missing labels or invalid ARIA.
3) Internationalization strategy
I separate content from logic using locale dictionaries keyed by message IDs. In Svelte, a lightweight store (or a library) exposes locale, t(id, params), and helpers for pluralization, gender, and date/number/currency formatting via Intl.*. Messages must be complete sentences, not concatenated fragments, to avoid grammar issues. I design components to accept formatted strings and directions (LTR/RTL) via context or props; layout switches to RTL with logical CSS properties (margin-inline, padding-inline, inset-inline) and dir attributes. Dynamic content is built with ICU message syntax or formatter functions so translators can handle plurals and placeholders safely. I ensure i18n coverage in tests: at least one non-English locale and an RTL snapshot to catch overflow and icon mirroring needs. Locale changes are reactive: stores update, components re-render, and any memoized layout recalculations recompute.
4) Responsive design and adaptive UX
For responsive design, I rely on fluid scales and design tokens (spacing, font sizes, radii) exposed as CSS variables. Layouts use flex and grid with minmax tracks and content-driven sizing. Where possible, I prefer container queries over global breakpoints so components adapt to their slot size, not just viewport width. Images use modern attributes (loading="lazy", width/height for CLS stability, srcset/sizes) and art direction when needed. I avoid desktop-only hover patterns; pointer and coarse input are detected via media queries, and interactive targets respect minimum touch sizes. On data-heavy components, I implement adaptive rendering: virtualized lists, skeletons, or progressive disclosure to keep mobile fast.
5) Maintainable code structure
Maintainability comes from isolation and contracts. Each component documents its props, slots, and events with TypeScript types and JSDoc. I keep styles scoped, using CSS variables for theming and avoiding deep selectors. A small state store per feature module prevents prop drilling; derived stores compute view state. Cross-cutting behaviors (focus trap, press, dismiss, portal) live as reusable actions. I publish primitives (e.g., Dialog, Popover, Combobox) with predictable keyboard maps and ARIA baked in, so product teams compose features without re-solving a11y each time. I enforce testing: unit tests for logic, interaction tests for keyboard and focus, and visual regression for RTL and breakpoints.
6) Performance without sacrificing quality
Accessibility and i18n are worthless if the page is slow. Svelte’s compiler helps, but I still optimize: code-split routes, lazy-load noncritical widgets, and avoid heavy client SDKs. For translations, I prebundle dictionaries per locale or stream them on demand with caching. I debounce resize and scroll effects, collapse observers per page, and use intersection observers to defer work. CSS prefers content-visibility and contain to keep layout cheap across breakpoints.
7) Governance and verification
Quality gates catch regressions: linters for a11y and styles, type checks, story-based previews for each component with a11y addon checks, and snapshots for LTR/RTL and small/large containers. CI runs Lighthouse or equivalent to track color contrast, tap targets, and best practices. Documentation includes usage guidelines, “do/dont” for copy length per locale, and examples for assistive tech.
By treating accessibility, internationalization, and responsive design as non-negotiable and embedding them into Svelte components via semantics, stores, actions, and tokens, I ensure inclusive UX and a codebase that remains maintainable as the product grows.
Table
Common Mistakes
- Adding ARIA everywhere instead of using semantic elements first.
- Ignoring keyboard order and focus restoration in dialogs and menus.
- Concatenating translatable fragments, breaking grammar and plurals.
- Forgetting RTL: hardcoded left/right instead of logical properties.
- Using viewport breakpoints only; components break inside narrow containers.
- Shipping synchronous locale loads that block rendering.
- Styling with deep selectors that leak and complicate theming.
- Skipping tests for keyboard, screen readers, and RTL; relying only on visual checks.
Sample Answers
Junior:
“I start with semantic HTML and add keyboard support. I use a translation store to render messages and format dates with Intl. For responsive design, I apply grid and fluid spacing. I document props and test focus behavior.”
Mid:
“I ship primitives with actions for focus trap and dismiss, plus slots for labels. I maintain locale dictionaries with ICU plurals and support RTL via logical CSS. Components use container queries and lazy image loading. Tests cover keyboard maps, RTL, and breakpoints.”
Senior:
“I set governance: a11y linting, i18n coverage, and responsive snapshots in CI. Svelte stores expose locale and formatters; tokens drive fluid design. Dialogs, popovers, and comboboxes follow WAI-ARIA patterns with roving tabindex. We prebundle per-locale chunks, enforce logical properties for RTL, and document typed contracts for maintainability.”
Evaluation Criteria
Look for an a11y-first plan: semantic elements, correct ARIA use, keyboard navigation, and focus control. Strong answers cover internationalization with message keys, ICU plurals, Intl formatting, and RTL via logical CSS and dir. Responsive design should mention fluid tokens, container queries, and adaptive rendering. Maintainability requires typed contracts, reusable actions, scoped styles, and tests. Red flags: ARIA overuse, string concatenation for i18n, viewport-only media, no RTL plan, and missing keyboard/focus tests.
Preparation Tips
- Build a Dialog and Combobox in Svelte with full keyboard maps and ARIA patterns.
- Implement locale and t() stores with ICU plurals; add an RTL locale and test icon flipping.
- Refactor CSS to logical properties; replace viewport media with container queries where relevant.
- Add Storybook stories for a11y checks, RTL, small/large containers, and high/low motion.
- Write Playwright tests for tab order, focus trap, and escape to close; include snapshots for RTL and small containers.
- Pre-split locale dictionaries, lazy-load noncritical ones, and verify no render blocking.
- Create a tokens file (spacing, type scale) and migrate components to variables for theming.
Real-world Context
- SaaS dashboard: Replacing ad-hoc dialogs with a reusable Svelte Dialog primitive cut a11y bugs to near zero and standardized keyboard behavior across features.
- E-commerce: Switching to logical CSS properties enabled instant RTL support; returns UI shipped to new markets without layout forks.
- Content platform: Container queries fixed card wrapping inside nested layouts, reducing CSS overrides and regressions.
- Global app: ICU plural rules and Intl.DateTimeFormat removed hardcoded strings; translation throughput increased while reviewers caught fewer errors.
Key Takeaways
- Use semantic HTML first; add ARIA only to fill gaps.
- Centralize i18n with message IDs, ICU plurals, Intl, and RTL via logical CSS.
- Make components responsive with tokens, container queries, and adaptive rendering.
- Keep Svelte components maintainable with typed contracts, actions, stores, and scoped styles.
- Verify with a11y linting, keyboard tests, RTL snapshots, and CI dashboards.
Practice Exercise
Scenario:
You are delivering a multilingual product page component set in Svelte: Dialog, Tabs, and ProductCard. Requirements include full keyboard access, RTL support, and responsive behavior within a narrow sidebar as well as a wide main area.
Tasks:
- Implement Dialog with focus trap, Escape to close, return-focus on dismiss, and aria-labelledby/aria-describedby. Provide slots for title, body, and actions; expose open as a bindable prop.
- Build Tabs with roving tabindex, Arrow key navigation, and aria-controls linking tabs to panels. Use semantic roles and ensure tabs are operable via keyboard and screen readers.
- Create ProductCard that adapts from a compact stacked layout to a two-column layout using container queries. Images specify width/height and lazy load.
- Add i18n stores with ICU messages for price, quantity, and stock status; include a fully translated RTL locale and apply dir on a container. Use logical CSS properties and verify mirrored icons where necessary.
- Provide a token file and CSS variables for spacing and type scale; components consume variables rather than hardcoded values.
- Write Playwright tests for keyboard flows, focus order, Escape behavior, and RTL snapshots.
- Run a11y linting and create Storybook stories for small/large containers, LTR/RTL, and reduced motion.
Deliverable:
A cohesive Svelte components set demonstrating accessibility, internationalization, and responsive design with maintainable contracts, strong tests, and production-ready ergonomics.

