Contributing
AWC UI is open source under MIT. PRs are welcome, especially from designers and developers who use it daily. This guide walks you through everything from cloning the repo to shipping a new component.
Prerequisites
Section titled “Prerequisites”| Tool | Version |
|---|---|
| Node.js | >= 18 |
| pnpm | >= 9 |
| Git | any recent |
git clone https://github.com/awc-ui/core.gitcd corepnpm installpnpm buildCold install runs in ~30s on a fast connection. The build emits Stencil’s dist-custom-elements, the technology wrappers, and the design tokens.
Local development
Section titled “Local development”# Start Storybook for visual development (most common)pnpm storybook
# Run unit tests in watch modepnpm --filter @awc-ui/core test:spec --watch
# Run lintpnpm lint:eslintpnpm lint:stylelint
# Build the docs sitebash scripts/build-docs.shStorybook hot-reloads as you edit .tsx and .css files. The docs site does not — you’ll need to rebuild after editing component readmes or generation scripts.
Monorepo structure
Section titled “Monorepo structure”packages/core/ Stencil web components (shadow DOM)packages/tokens/ MD3 design tokens (CSS custom properties)packages/angular/ Angular wrappers (auto-generated)packages/react/ React wrappers (auto-generated)packages/vue/ Vue wrappers (auto-generated)packages/svelte/ Svelte wrappers (auto-generated)apps/storybook/ Storybook 8 (web-components-vite)apps/docs/ Astro Starlight documentation sitedocs/ Markdown guides + LLM manifestscripts/ Build, generation, and audit scripts.github/workflows/ CI/CD pipelinesNaming conventions
Section titled “Naming conventions”AWC UI follows a strict naming scheme — pick the right name once and the rest of the patterns fall into place automatically.
| Concept | Pattern | Example |
|---|---|---|
| Tag | md-{name} | md-button, md-text-field |
| Class | Md{PascalName} | MdButton, MdTextField |
| Host CSS class | md-{name} | md-button |
| Modifier class | md-{name}--{modifier} | md-button--filled |
| Element class | md-{name}__{element} | md-button__label |
| Event | md{PascalAction} | mdClick, mdChange, mdOpen |
| CSS public var | --md-{name}-{property} | --md-button-container-color |
| CSS internal var | --_{property} | --_container-color |
Adding a new component
Section titled “Adding a new component”1. Create the component directory
Section titled “1. Create the component directory”packages/core/src/components/md-{name}/ md-{name}.tsx Component logic (Stencil .tsx) md-{name}.css Styles (tokens, RTL, states) md-{name}.spec.ts Unit tests (newSpecPage) md-{name}.e2e.ts E2E tests (newE2EPage) — optional but preferred readme.md Documentation (hand-written + auto-generated)2. Implement the component
Section titled “2. Implement the component”Required patterns for every component:
shadow: truein@Component- All props have JSDoc comments and sensible defaults
- Custom events are prefixed with
md(e.g.mdClick,mdChange) - All styleable internal elements have a
partattribute - All layout uses CSS logical properties (
inset-inline-start,padding-inline, etc.) — neverleft/right/margin-left - All colors / shapes / elevations / typography reference design tokens (
var(--md-sys-color-*), never hardcoded) - State layers implemented at MD3 spec opacities (8% hover, 12% focus, 12% press)
- Keyboard handlers (Enter, Space, Escape, Arrows) per WAI-ARIA Authoring Practices
- ARIA role +
aria-disabled+tabindexmanagement on the host
For a worked example of every point above, read an existing component end to
end — packages/core/src/components/md-checkbox/ is small enough to hold in
your head and exercises the form-association, ARIA and density patterns.
3. Write unit tests
Section titled “3. Write unit tests”Every spec must cover, at minimum:
- Rendering with defaults and all variants
- Reflected attributes and prop defaults
- ARIA roles and attributes
- Event emission and detail payloads
- Disabled state preventing interaction
- Keyboard navigation
- Slot rendering
- CSS parts exposure (
partattribute presence) - RTL context rendering (
<div dir="rtl">)
pnpm --filter @awc-ui/core test:spec4. Write a Storybook story
Section titled “4. Write a Storybook story”Create apps/storybook/src/stories/Md{Name}.stories.ts with these stories:
Playground— interactive controls for every propAllVariants— every variant side by sideStates— enabled / disabled / soft-disabled / loading / focused / selectedRTL— wrapped in<div dir="rtl">DarkTheme— wrapped in<div data-theme="dark">CustomCSS— CSS custom-property overridesCSSParts—::part()styling examples
Storybook stories also serve as the source for accessibility regression tests (pnpm test:a11y).
5. Write the readme
Section titled “5. Write the readme”The readme.md in the component directory must include hand-written content above the <!-- Auto Generated Below --> marker:
- Description (with link to the MD3 spec)
- Installation
- Usage examples
- Variants table
- Sizes table (if applicable)
- States documentation
- Accessibility section (ARIA, keyboard, screen reader)
- RTL section
- CSS custom properties table
- CSS parts table
- Slots documentation
The hand-written content is included in the LLM manifest verbatim.
6. Regenerate generated artifacts
Section titled “6. Regenerate generated artifacts”# Regenerate the LLM manifest (used by AI tools)pnpm generate:llm
# Regenerate documentation pages and aggregate JSONpnpm generate:docsQuality checklist
Section titled “Quality checklist”Run before opening a PR:
-
pnpm lint:eslintpasses (no warnings) -
pnpm lint:stylelintpasses (no warnings) -
pnpm --filter @awc-ui/core test:specpasses -
pnpm sizepasses (your component within budget) - Storybook stories render correctly in Chromium, Firefox, and WebKit
- Manual screen-reader pass on the new component (NVDA or VoiceOver)
- RTL test added and passing
- Dark mode renders correctly
- The component’s
readme.mdis created or updated — it is the manual that ships to npm, so it is part of the change, not a follow-up -
main-llm.md’s component inventory and decision matrix mention the component - A changeset added (
pnpm changeset) describing the change
Commit convention
Section titled “Commit convention”We follow Conventional Commits:
feat(button): add soft-disabled statefix(text-field): correct focus ring in RTLdocs(checkbox): add accessibility sectiontest(switch): add keyboard navigation testschore(deps): bump @stencil/core to 4.xThe CI pipeline rejects PRs that touch packages/* without an accompanying changeset.
CI / CD
Section titled “CI / CD”Every PR runs the full quality pipeline:
- Install with pnpm (cached)
- Lint (ESLint + Stylelint, max-warnings 0)
- Unit tests (Jest via Stencil)
- Build (all packages + technology wrappers)
- Accessibility tests (axe via
@storybook/test-runner) - Changeset check (require changeset for any
packages/*change) - Docs build (
bash scripts/build-docs.sh— Astro + Pagefind + Storybook embed)
On merge to main, the docs site auto-deploys to Netlify (awc-ui.dev). Tagged releases publish to npm under the @awc-ui scope with Sigstore provenance.
Working with AI agents
Section titled “Working with AI agents”The repository ships its own machine-readable context, and it is the same context the published package carries:
| File | What it gives an agent |
|---|---|
main-llm.md | The build director: interview, decision matrix, token reference, composition rules, page recipes, ship checklist |
packages/core/src/components/<tag>/readme.md | One component: when to use it, when not to, full API, accessibility contract, anti-patterns |
Point your assistant at main-llm.md first — it routes to the right component
rather than letting the model pick by name-similarity — then at that
component’s readme.md before writing its markup.
Working in a project that only consumes the package, run npx awc-ui ai-setup
there instead: it writes the same pointers into AGENTS.md, CLAUDE.md,
.cursor/rules/ and .github/copilot-instructions.md, aimed at the copies
installed in node_modules. See Building with AI.
Raising an issue
Section titled “Raising an issue”You do not need to write code to help — a report we can reproduce is worth more than a patch we cannot verify. Each of these has its own template, and its own guide for what makes it actionable:
| You want to | Guide |
|---|---|
| Report something broken | Reporting a bug |
| Ask for a prop, variant or event on an existing component | Requesting a feature |
| Ask for a component that does not exist yet | Requesting a component |
Start at new issue and pick the matching template.
- General questions — Discussions. No template, no triage, usually a faster answer.
- Security vulnerabilities — report privately via a security advisory, never as a public issue.