Building Type-Safe APIs with Nuxt 3 and Prisma
Learn how to build end-to-end type-safe APIs using Nuxt 3 server routes and Prisma ORM for a seamless developer experience.
Accessibility isn't an afterthought. Learn to build inclusive web apps with semantic HTML, keyboard navigation, and ARIA done right.
Mbeah Essilfie
June 9, 2026 at 06:03 AM
1 in 4 adults in the US has a disability. Accessibility isn't just ethical — it's practical. Accessible apps work better for everyone: keyboard power users, people with slow connections, users of screen readers, and people in bright sunlight.
<!-- ❌ Div soup -->
<div class="header">
<div class="nav">
<div class="link" onclick="navigate()">Home</div>
</div>
</div>
<!-- ✅ Semantic HTML — free accessibility -->
<header>
<nav aria-label="Main navigation">
<a href="/">Home</a>
</nav>
</header>
Semantic elements provide meaning to assistive technology without extra attributes.
Every interactive element must be keyboard-accessible:
<template>
<div
role="tablist"
@keydown.left="selectPrev"
@keydown.right="selectNext"
@keydown.home="selectFirst"
@keydown.end="selectLast"
>
<button
v-for="(tab, i) in tabs"
:key="tab.id"
role="tab"
:tabindex="i === activeIndex ? 0 : -1"
:aria-selected="i === activeIndex"
@click="select(i)"
>
{{ tab.label }}
</button>
</div>
</template>
When content changes dynamically, manage focus:
// After opening a modal
function openModal() {
isOpen.value = true
nextTick(() => {
modalRef.value?.focus()
})
}
// After deleting an item from a list
function deleteItem(index: number) {
items.value.splice(index, 1)
nextTick(() => {
// Focus the next item, or previous if it was the last
const nextIndex = Math.min(index, items.value.length - 1)
itemRefs.value[nextIndex]?.focus()
})
}
<!-- ❌ Color only -->
<span class="text-red-500">Error</span>
<!-- ✅ Color + icon + text -->
<span class="text-red-500 flex items-center gap-1">
<IconAlertCircle aria-hidden="true" />
Error: Email is required
</span>
The first rule of ARIA: don't use ARIA if native HTML does the job.
<!-- ❌ Over-engineered -->
<div role="button" tabindex="0" aria-pressed="false" onclick="...">
<!-- ✅ Just use a button -->
<button>Click me</button>
Build for everyone from the start. It's always cheaper than retrofitting.
Fullstack Software Developer
Learn how to build end-to-end type-safe APIs using Nuxt 3 server routes and Prisma ORM for a seamless developer experience.
Go beyond basic utility classes and learn how to build cohesive, maintainable design systems with Tailwind CSS.
Understand the power of Vue 3's Composition API through practical, real-world composable patterns that you can use today.
