This episode covers accessibility and user experience: ARIA roles, keyboard navigation and focus management, semantic HTML and accessible forms, responsive layout and inclusive design, plus the fundamentals of internationalization and localization.

Accessible applications are not just an ethical obligation — they also widen the reach of users and raise the quality of experience for everyone. Episode 17 covers accessibility and UX in SvelteKit: ARIA roles, keyboard navigation, semantic HTML, accessible forms, inclusive design, plus the fundamentals of internationalization.
The principle is simple: everyone, whatever assistive technology they use, should be able to use the application equally. Screen readers, keyboard users, and touch screens all deserve a complete experience, not a reduced version.
After this episode, you can build assistive-friendly interfaces, forms that are easy to understand, and structures ready to be translated into many languages.
Semantic elements like header, nav, main, footer, and h1 through h6 provide structure that screen readers can understand. Correct structure matters even more than ARIA attributes: use native elements first, and add ARIA only when a native element is not enough.
<a class="skip-link" href="#konten">Lewati ke konten utama</a>
<nav aria-label="Navigasi utama">
<ul>
<li><a href="/">Beranda</a></li>
<li><a href="/artikel">Artikel</a></li>
</ul>
</nav>
<main id="konten">
<h1>Judul halaman</h1>
</main>When content changes asynchronously, such as an error message or search results, screen readers need to be told. The aria-live="polite" attribute announces the change without forcibly moving the user's focus.
<script>
let hasil = $state([]);
let sedangMencari = $state(false);
</script>
<p aria-live="polite">
{#if sedangMencari}Mencari...{:else}{hasil.length} hasil ditemukan{/if}
</p>Make sure the tab order follows the visual and logical flow: navigation, main content, then secondary actions. Native interactive elements like a, button, and input are focusable by default; avoid making non-interactive elements focusable without a real need.
When opening a dialog, move focus to the first element and return it to the trigger when the dialog closes. When navigating between routes, make sure the page title and focus change so screen reader users know the new context.
Every input needs a label connected through the for and id attributes. Error messages are linked with aria-describedby, and aria-invalid marks the input that failed validation so users relying only on keyboard or screen readers still understand what is wrong.
<script>
let nama = $state("");
let error = $state("");
</script>
<form method="POST" action="?/simpan">
<label for="nama">Nama lengkap</label>
<input
id="nama"
name="nama"
bind:value={nama}
aria-invalid={error ? "true" : "false"}
aria-describedby={error ? "error-nama" : undefined}
/>
{#if error}
<p id="error-nama" class="error" role="alert">{error}</p>
{/if}
</form>Inclusive design starts with a layout that works on small screens and then grows. Use relative units, container queries, and make sure text contrast meets the recommended ratio. Do not rely on color as the only indicator of status — add an icon or text.
<span class="status status-ok" role="status">Tersedia</span>A globally ready application separates all text from code. Store translations in one centralized structure and choose the language based on user preference, the lang attribute on the HTML, or the URL such as /en and /id. Libraries like paraglide-svelte make this flow easier in SvelteKit; install with npm install -D @inlang/paraglide-sveltekit and follow the setup guide.
export const terjemahan = {
id: { sapa: "Halo dunia", cari: "Cari" },
en: { sapa: "Hello world", cari: "Search" }
};
export const terjemahkan = (locale, kunci) =>
terjemahan[locale]?.[kunci] ?? kunci;Key takeaways:
aria-live.for and aria-describedby.In the next episode we get into architecture & maintainability: feature-based structure and modular routing, separation of concerns between UI, data, and server logic, reusable composables and utility modules, plus scalable code organization for teams.