Skip to main content
VelinStyle v0.8.0
  1. Docs
  2. Getting Started
  3. A11y patterns

Accessibility patterns

Minimal HTML snippets for WCAG-aligned structure. Combine with form validation and Velin components such as velin-dialog and velin-tabs. These patterns are not a substitute for testing with assistive technologies.

Important: The full pattern reference and sample page live in the VelinStyle repository under docs/a11y-patterns/ and samples/a11y-patterns.html. This page mirrors the essentials for the public docs site.

Skip link and focus

VelinStyle ships .velin-skip-link (and skip-link utilities in docs) plus :focus-visible styles. Point to your main landmark with href="#main-content" (or #main).

<a href="#main-content" class="velin-doc-skip">Skip to main content</a>
…
<main id="main-content">…</main>

Live regions

Use role="status" with aria-live="polite" for non-urgent updates; role="alert" (assertive) only when users must be interrupted immediately.

<div id="save-status" role="status" aria-live="polite" class="text-muted"></div>

Dialog

For focus trap and Escape handling, prefer <velin-dialog> or follow the WAI-ARIA dialog pattern. Markup should set aria-modal="true" and reference a label and description.

<div class="velin-modal-overlay" data-velin-open role="presentation">
  <div class="velin-modal" role="dialog" aria-modal="true"
       aria-labelledby="dlg-title" aria-describedby="dlg-desc">
    <h2 id="dlg-title" class="velin-modal__title">Title</h2>
    <div id="dlg-desc" class="velin-modal__body">…</div>
  </div>
</div>

Tabs

Prefer <velin-tabs> for keyboard support. Static structure example:

<div role="tablist" aria-label="Settings">
  <button type="button" role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1">General</button>
  <button type="button" role="tab" aria-selected="false" aria-controls="panel-2" id="tab-2">Security</button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">…</div>
<div role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>…</div>

Landmarks

<body>
  <header>…</header>
  <nav aria-label="Primary">…</nav>
  <main id="main-content">…</main>
  <aside aria-label="Related">…</aside>
  <footer>…</footer>
</body>

Forms and errors

Associate errors with aria-describedby; set aria-invalid="true" when invalid. Optional layer: src/components/form-validation.css adds :user-invalid styling, .velin-field-error, and .velin-field-hint — see Validation.

<label class="velin-label" for="email">Email</label>
<input id="email" class="velin-input" aria-invalid="true" aria-describedby="email-err">
<p class="velin-field-error" id="email-err">Invalid address.</p>

Use <velin-dropdown> with role="menuitem" and type-ahead (0.7.0).

<velin-dropdown>
  <button slot="trigger">Actions</button>
  <button role="menuitem">Edit</button>
</velin-dropdown>

Disclosure (collapse)

<velin-collapse>
  <button slot="trigger" type="button">Details</button>
  <p>Content…</p>
</velin-collapse>

Data table

<div class="velin-table-wrapper">
  <table class="velin-table">
    <caption>Sales</caption>
    <th scope="col">Region</th>
  </table>
</div>

Loading / busy

<section aria-busy="true" aria-live="polite">
  <div class="velin-skeleton velin-skeleton--heading"></div>
</section>

Theme wählen