When building modern web applications, it’s easy to get caught up in trendy designs and interactive features while unintentionally leaving accessibility behind. But accessible components aren’t just “nice to have”, they’re essential for creating inclusive experiences. In this post, we’ll look at how to build accessible components with Tailwind CSS and Vue, ensuring our applications are usable by everyone.
Why Accessibility Matters
Accessibility is about making sure people of all abilities can use your website or app. This includes users who navigate with a keyboard, rely on screen readers, or need higher contrast for readability.
Ignoring accessibility can create frustrating, and sometimes unusable, experiences. By baking accessibility into your components from the start, you reduce barriers and expand your app’s reach.
Setting Up Tailwind and Vue
If you’re starting fresh, you can spin up a Vue project and add Tailwind:
npm init vue@latest my-app
cd my-app
npm install
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Update tailwind.config.js and add Tailwind’s base styles to main.css.
Now you’re ready to start building accessible components.
Example 1: Accessible Button
Buttons often look great but miss important details like focus states and ARIA labels. With Tailwind, you can make a button that is both stylish and accessible.
<template>
<buttonclass="px-4 py-2 bg-blue-600 text-white rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-400 hover:bg-blue-700"aria-label="Submit form">
Submit
</button>
</template>
The button includes a visible focus ring so keyboard users can easily see when it’s active, an ARIA label to provide extra clarity for screen reader users, and distinct hover and focus states that give clear visual feedback.
Example 2: Accessible Modal
Modals can be tricky because they interrupt normal page flow. Let’s build one in Vue that handles accessibility correctly.
<template>
<div v-if="open" class="fixed inset-0 flex items-centre justify-centre bg-black bg-opacity-50">
<div
class="bg-white p-6 rounded-lg shadow-lg max-w-md w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
>
<h2 id="modal-title" class="text-lg font-bold mb-4">Confirmation</h2>
<p>Are you sure you want to continue?</p>
<div class="mt-6 flex justify-end space-x-2">
<button @click="confirm" class="px-4 py-2 bg-blue-600 text-white rounded">Yes</button>
<button @click="close" class="px-4 py-2 bg-grey-200 rounded">Cancel</button>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const open = ref(true)
const confirm = () => { open.value = false }
const close = () => { open.value = false }
</script>
The modal uses role=”dialog” and aria-modal=”true” to help screen readers understand its context, while aria-labelledby=”modal-title” links the heading to the dialogue for clarity. Tailwind utilities handle the spacing, shadows, and responsive styling, ensuring the modal looks polished and functions well across devices.
Example 3: Accessible Toggle Switch
Switches should be operable with both mouse and keyboard. Let’s create one with Tailwind’s utility classes.
<template>
<button
:aria-pressed="enabled.toString()"
@click="enabled = !enabled"
class="w-12 h-6 flex items-centre rounded-full transition-colours"
:class="enabled ? 'bg-green-500' : 'bg-grey-300'"
>
<span
class="w-5 h-5 bg-white rounded-full shadow transform transition-transform"
:class="enabled ? 'translate-x-6' : 'translate-x-1'"
></span>
</button>
</template>
<script setup>
import { ref } from 'vue'
const enabled = ref(false)
</script>
The toggle switch uses aria-pressed to communicate its state to assistive technology, provides clear visual on/off states using Tailwind colours and transforms, and is fully operable via keyboard using the Space or Enter keys.
Best Practices for Accessible Components
- Always include focus states – Tailwind’s focus:ring utilities are your friend.
- Use semantic HTML before adding ARIA attributes.
- Test with a keyboard – Can you navigate without a mouse?
- Check colour contrast – Tailwind’s colour palette makes this easier, but tools such as contrast-ratio.com help verify.
- Use Vue’s reactivity to keep accessibility states in sync (e.g., aria-expanded, aria-pressed).
Wrapping Up
By combining Vue’s reactivity with Tailwind’s utility-first styling, you can build components that are both attractive and accessible. It’s not just about compliance, it’s about making your application inclusive for everyone.
Accessibility is a journey, not a tick-box exercise. Start with small steps – like accessible buttons, modals, and switches and expand from there.