Getting Started with HTML5 Web Components

Standard, framework-agnostic Custom Elements built for WCAG 2.1/2.2 AA & AAA compliance. Usable in plain HTML, Vue, Svelte, Angular, Astro, WordPress, Rails, and React.

Building a dedicated React application? Check out the Getting Started with React guide for idiomatic React props, forwardRefs, and hooks.

Why Standard Web Components?

Accessibility shouldn't be locked to a single UI framework. By providing standard HTML Custom Elements via @a11ypros/a11y-ui-elements, developers can drop accessible components into any stack:

  • 100% Light DOM Accessibility: Unlike typical web components that hide markup inside a Shadow Root (breaking cross-boundary ARIA associations like aria-labelledby, aria-describedby, and <label for="...">), our components render directly in the Light DOM. Screen readers navigate standard semantic HTML without barriers.
  • Zero External Runtime: Zero third-party dependencies. Ultra-lightweight footprint.
  • Universal Styling: Reuses your existing design tokens and CSS custom properties without needing complex ::part() selectors.

1. Installation

Install via npm for module bundlers (Vite, Webpack, Next.js, Nuxt, SvelteKit):

npm install @a11ypros/a11y-ui-elements @a11ypros/a11y-ui-components

Import into your app (recommended)

Just like CrowdStrike Glide Core, import the element once in your app or component entry point. The custom element is registered automatically:

import '@a11ypros/a11y-ui-elements/switch';
import '@a11ypros/a11y-ui-elements/button';

// Or import all elements:
import '@a11ypros/a11y-ui-elements';

Then use the tag directly in your markup without any script tags:

<a11y-switch label="Notifications" checked></a11y-switch>
<a11y-button variant="primary">Submit</a11y-button>

Without a bundler (Static HTML / CMS)

For static sites, WordPress, or Rails without an npm pipeline, load the standalone bundle:

<!-- Stylesheet with tokens & component styles -->
<link rel="stylesheet" href="path/to/@a11ypros/a11y-ui-components/styles/global.css">
<link rel="stylesheet" href="path/to/@a11ypros/a11y-ui-components/styles/components.css">

<!-- Self-contained Web Components bundle -->
<script src="path/to/@a11ypros/a11y-ui-elements/dist/bundle.js"></script>

Interactive Switch Example

Toggle between React and Web Component / HTML syntax to see how the component behaves identically.

Interactive Preview

Interactive Button Example

Custom elements support all variants, keyboard navigation, and loading states.

Interactive Preview

Using with Your Favorite Framework

Vue 3

Tell Vite/Vue to recognize <a11y-*> tags as custom elements in your vite.config.ts:

import vue from '@vitejs/plugin-vue';

export default {
  plugins: [
    vue({
      template: {
        compilerOptions: {
          isCustomElement: (tag) => tag.startsWith('a11y-'),
        },
      },
    }),
  ],
};

Then use it directly in any Vue template:

<template>
  <a11y-switch :checked="isEnabled" @change="onToggle" label="Dark Mode" />
  <a11y-button variant="primary" :loading="isSubmitting">Submit</a11y-button>
</template>

Svelte

Svelte supports custom elements natively. Import the package once and use the tags:

<script>
  import '@a11ypros/a11y-ui-elements';
  let checked = false;
</script>

<a11y-switch label="Notifications" {checked} on:change={(e) => checked = e.detail.checked} />

React 19

React 19 includes native custom element support, automatically passing properties, attributes, and listening to custom events:

import '@a11ypros/a11y-ui-elements';

export function Settings() {
  return (
    <a11y-switch
      label="Sound Effects"
      checked={true}
      onChange={(e) => console.log(e.detail.checked)}
    />
  );
}