Accessibility

Back

Loading concept...

🚪 Svelte Accessibility Basics: Building Doors Everyone Can Open


The Magic Door Analogy 🚪✨

Imagine you’re building a door to a magical playground. Some kids can see the door, some can hear it, some feel for it with their hands. A great door works for ALL kids!

Accessibility (we call it a11y for short) means making your Svelte apps work for everyone—people who use screens, people who use voices, people who use keyboards, and more!


What is Accessibility? 🎯

Think of your website like a toy store:

  • Some visitors can see the toys on shelves
  • Some visitors listen to someone describe the toys
  • Some visitors feel their way around

Accessibility = Making sure EVERYONE can enjoy the toy store!

<!-- BAD: Only works if you can see -->
<div on:click={buyToy}>
  Buy Toy
</div>

<!-- GOOD: Works for everyone! -->
<button on:click={buyToy}>
  Buy Toy
</button>

Why the button is better:

  • Screen readers announce “Buy Toy, button”
  • Keyboards can focus and activate it
  • It’s the right tool for the job!

The Four Super Powers of Accessibility 🦸

1. Perceivable 👁️👂

Can everyone sense the content?

Like a storybook that can be read aloud OR looked at pictures:

<img
  src="puppy.jpg"
  alt="A fluffy golden puppy playing with a red ball"
/>

The alt text is like describing the picture to a friend who can’t see it.

2. Operable 🎮

Can everyone USE the controls?

Like a game controller that works with buttons, not just touch:

<script>
  function handleAction() {
    // Do something fun!
  }
</script>

<!-- Works with mouse AND keyboard -->
<button on:click={handleAction}>
  Play Game
</button>

3. Understandable 🧠

Does everything make sense?

Like clear instructions in a recipe:

<label for="name-input">
  What's your name?
</label>
<input
  id="name-input"
  type="text"
  placeholder="Type your name here"
/>

4. Robust 💪

Does it work everywhere?

Use standard HTML that all browsers understand:

<!-- Use real HTML elements -->
<nav>Navigation here</nav>
<main>Main content here</main>
<footer>Footer here</footer>

Semantic HTML: Speaking the Right Language 📝

Semantic means “has meaning.” It’s like using the right word:

Wrong Word Right Word Why
“thingy” “door” Clear!
<div> <button> Clear!
<span> <h1> Clear!
<!-- ❌ This is confusing -->
<div class="button" on:click={submit}>
  Submit
</div>

<!-- ✅ This is clear! -->
<button type="submit">
  Submit
</button>

The Semantic Family 👨‍👩‍👧‍👦

graph TD A["Document"] --> B["header"] A --> C["nav"] A --> D["main"] A --> E["footer"] D --> F["article"] D --> G["section"] D --> H["aside"]

Example in Svelte:

<header>
  <h1>My Pet Store</h1>
</header>

<nav>
  <a href="/dogs">Dogs</a>
  <a href="/cats">Cats</a>
</nav>

<main>
  <article>
    <h2>Meet Fluffy!</h2>
    <p>Fluffy loves belly rubs.</p>
  </article>
</main>

<footer>
  <p>© Pet Store 2024</p>
</footer>

ARIA: The Secret Helper Language 🗣️

Sometimes HTML needs extra help. ARIA (Accessible Rich Internet Applications) adds invisible labels!

Think of ARIA like name tags at a party—they tell everyone who’s who!

Common ARIA Attributes:

<script>
  let isOpen = false;
  let items = ['Apple', 'Banana', 'Cherry'];
</script>

<!-- Label for screen readers -->
<button aria-label="Close menu">
  ✕
</button>

<!-- Describe current state -->
<button
  aria-expanded={isOpen}
  on:click={() => isOpen = !isOpen}
>
  Menu
</button>

<!-- Live announcements -->
<div
  aria-live="polite"
  role="status"
>
  {items.length} items in cart
</div>

The Golden Rule of ARIA ⚠️

“No ARIA is better than bad ARIA”

Only use ARIA when HTML can’t do the job!

<!-- ❌ Unnecessary ARIA -->
<button role="button">Click me</button>

<!-- ✅ HTML already says it's a button! -->
<button>Click me</button>

Keyboard Navigation: The Tab Adventure 🎹

Some people navigate using ONLY the keyboard. Make sure they can!

The Tab Order Journey:

graph LR A["Start"] --> B["Link 1"] B --> C["Button"] C --> D["Input"] D --> E["Link 2"]

Making Elements Focusable:

<script>
  function handleKeydown(event) {
    if (event.key === 'Enter' || event.key === ' ') {
      // Do the action!
    }
  }
</script>

<!-- Naturally focusable -->
<button>I'm focusable!</button>
<a href="/page">Me too!</a>
<input type="text" />

<!-- Make a div focusable (if you must) -->
<div
  tabindex="0"
  role="button"
  on:keydown={handleKeydown}
  on:click={() => console.log('clicked')}
>
  Custom Button
</div>

TabIndex Values:

Value Meaning
0 Add to normal tab order
-1 Focusable by code only
1+ ⚠️ Avoid! Changes order!

Focus Management in Svelte 🎯

Using bind:this for Focus:

<script>
  let inputElement;
  let showForm = false;

  function openForm() {
    showForm = true;
    // Wait for DOM update, then focus
    setTimeout(() => {
      inputElement?.focus();
    }, 0);
  }
</script>

<button on:click={openForm}>
  Open Form
</button>

{#if showForm}
  <input
    bind:this={inputElement}
    type="text"
    placeholder="Type here..."
  />
{/if}

Better: Using tick():

<script>
  import { tick } from 'svelte';

  let inputElement;
  let showForm = false;

  async function openForm() {
    showForm = true;
    await tick(); // Wait for Svelte to update
    inputElement?.focus();
  }
</script>

Color & Contrast: Seeing Clearly 🎨

Colors need enough contrast so everyone can read them!

Contrast Ratio Rules:

Text Size Minimum Ratio
Normal text 4.5:1
Large text (18px+) 3:1
<style>
  /* ❌ Hard to read */
  .bad {
    color: #aaa;
    background: #fff;
  }

  /* ✅ Easy to read */
  .good {
    color: #333;
    background: #fff;
  }
</style>

<p class="good">I'm easy to read!</p>

Don’t Rely on Color Alone:

<!-- ❌ Color only -->
<span style="color: red;">Error</span>

<!-- ✅ Color + icon + text -->
<span style="color: red;">
  ⚠️ Error: Please enter your name
</span>

Forms: Making Inputs Friendly 📋

Every input needs a label—like putting names on mailboxes!

The Perfect Form Field:

<script>
  let email = '';
  let error = '';

  function validate() {
    if (!email.includes('@')) {
      error = 'Please enter a valid email';
    } else {
      error = '';
    }
  }
</script>

<div>
  <label for="email">Email Address</label>
  <input
    id="email"
    type="email"
    bind:value={email}
    on:blur={validate}
    aria-describedby={error ? 'email-error' : null}
    aria-invalid={error ? 'true' : 'false'}
  />
  {#if error}
    <p id="email-error" role="alert">
      {error}
    </p>
  {/if}
</div>

Required Fields:

<label for="name">
  Name <span aria-hidden="true">*</span>
  <span class="sr-only">(required)</span>
</label>
<input
  id="name"
  type="text"
  required
  aria-required="true"
/>

<style>
  .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    border: 0;
  }
</style>

Screen Reader Only Text 🔇➡️🔊

Sometimes you need to add text only screen readers can hear:

<style>
  .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
</style>

<button>
  <span class="sr-only">Add to cart:</span>
  🛒
  <span class="sr-only">Shopping cart</span>
</button>

Testing Your Accessibility 🧪

Quick Checks:

  1. Keyboard test: Unplug your mouse. Can you use everything?
  2. Zoom test: Zoom to 200%. Does it still work?
  3. Screen reader: Try VoiceOver (Mac) or NVDA (Windows)

Svelte A11y Warnings:

Svelte helps you! It shows warnings for common mistakes:

<!-- Svelte warns: "A11y: <img> should have an alt" -->
<img src="cat.jpg" />

<!-- Fixed! -->
<img src="cat.jpg" alt="Orange tabby cat sleeping" />

Quick Reference Card 📝

Element Use For
<button> Clickable actions
<a> Navigation links
<input> User text entry
<label> Input descriptions
<h1>-<h6> Headings (in order!)
<nav> Navigation sections
<main> Main content
<header> Page/section headers
<footer> Page/section footers

You Did It! 🎉

You now know the basics of making Svelte apps accessible:

✅ Use semantic HTML (the right element for the job) ✅ Add ARIA only when needed ✅ Ensure keyboard navigation works ✅ Maintain color contrastLabel all form inputs ✅ Test with keyboard and screen readers

Remember: Accessibility isn’t extra work—it’s building the door that everyone can open! 🚪✨


“The power of the Web is in its universality. Access by everyone regardless of disability is an essential aspect.” — Tim Berners-Lee, inventor of the World Wide Web

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.