Accessible Collapsible Accordion in Svelte with Melt UI
Why choose Melt UI + Svelte for collapsible UI components?
Melt UI provides headless primitives built for Svelte: small, accessible building blocks that don’t dictate markup or styles. For a collapsible/accordion, that means you get the focus/keyboard logic and aria contract handled while keeping full control of the DOM and CSS. If you like tiny bundles and predictable hydration with SvelteKit, it’s a logical combo.
Headless libraries keep semantics consistent across your app without locking you into a specific look — perfect for design systems that glue Tailwind utilities, custom tokens, and TypeScript types. Melt UI specifically targets Svelte, so you avoid the adapter overhead required to use non-Svelte primitives.
Finally, accessibility is not an optional patch here. Melt UI implements keyboard handling and A11y attributes aligned to the WAI‑ARIA Authoring Practices, but you still must verify markup and test with assistive tech. Consider Melt UI as the wiring; you still supply the light fixtures.
Implementing an accessible accordion: code and behavior
Below is a pragmatic Svelte + Melt UI example that shows the typical structure: a parent accordion (optional multi/open behavior), triggers, and content sections. Melt UI names may differ with versions, but the pattern shown is stable: trigger toggles, content reveals, aria attributes sync.
// src/routes/Accordion.svelte
<script lang="ts">
import {
Collapsible,
CollapsibleTrigger,
CollapsibleContent
} from 'melt-ui'; // ensure version compatibility
export let multi = false; // allow multiple panels open
</script>
<Collapsible {multi} class="space-y-2">
<div class="border rounded">
<CollapsibleTrigger class="w-full px-4 py-3 text-left flex justify-between items-center bg-gray-50">
<span>Section A</span>
<span aria-hidden>▾</span>
</CollapsibleTrigger>
<CollapsibleContent class="px-4 py-3">
<p>Content A — accessible and lazily-mounted as needed.</p>
</CollapsibleContent>
</div>
<!-- Repeat sections -->
</Collapsible>
Key behaviors to verify: triggers must expose aria-expanded (true/false) and aria-controls matching the collapsible content ID. Content containers should use role=”region” and aria-labelledby when appropriate. Melt UI usually wires these attributes for you, but inspect the DOM and ensure IDs are unique.
Keyboard interactions: Enter/Space should toggle a panel; when in an accordion (single-open) pattern, Up/Down (or Home/End) should move focus between triggers. Test with keyboard only and with screen readers (NVDA, VoiceOver) to ensure announcements and focus are intuitive.
Styling, TypeScript, and Tailwind integration
Since Melt UI is headless, use Tailwind utility classes directly on triggers and content. This provides rapid prototyping and consistent visual language with your design system. If you prefer CSS modules or SCSS, the approach is identical: apply classes to the semantic elements Melt UI exposes.
TypeScript: annotate component props and events. With Svelte + TS, type exported props and create typed events for custom interactions. Example: export let multi: boolean = false; for props and define interfaces for payloads if you emit custom events from the trigger or content.
Performance: lazy-mount heavy content or images inside <CollapsibleContent> to defer rendering until open. Use Svelte’s {#if open} blocks when you control open state to further reduce initial render cost. Keep ARIA attributes while lazy-mounting to avoid losing semantic connection.
Accessible vanilla alternative (when not using Melt UI)
If you prefer zero-dependency or need a custom behavior, implement an accessible accordion with a few rules: use button elements for triggers, synchronize aria-expanded and aria-controls, give content an ID and role=”region”. Manage focus movement and keyboard handlers explicitly. It’s more code but gives total control.
Small vanilla pattern overview:
- Markup: <button aria-expanded=”false” aria-controls=”panel-1″>Trigger</button>
- Panel: <div id=”panel-1″ role=”region” aria-labelledby=”trigger-1″>…</div>
This enforces semantic correctness and is friendly to assistive tech.
Keyboard details you must implement: Space/Enter toggles, Arrow Up/Down navigates between triggers (for single-select accordions), Home/End jumps to first/last triggers. Also ensure focus trapping isn’t applied erroneously inside content—users need natural tab order.
Accessibility checklist & testing
Before shipping, run through this checklist: keyboard-only operation, screen reader announcements, correct aria-expanded/aria-controls relationship, focus order, and visual focus indicator. If your content changes height on open, ensure animations don’t disrupt users—avoid pure CSS transforms that hide content from assistive tech.
Automated tools help but don’t replace manual testing. Use Lighthouse for basic checks, axe-core for rule-based scanning, but also test with NVDA (Windows) or VoiceOver (macOS/iOS). Keyboard navigation tests are best done manually while watching attributes change in DevTools.
Also validate semantics for SEO and feature snippets: accordions with clear heading-like triggers and HTML content are more likely to be indexed properly. Keep headings and answers concise if you aim for a featured snippet for FAQ-style content.
Links & references (backlinks to authoritative sources)
Use these primary resources while implementing or auditing:
- Melt UI (official)
- Headless UI primitives for Svelte — ideal entry point for collapsible/accordion primitives.
- Svelte docs
- Core component patterns, reactivity, and Svelte+TypeScript guidance.
- Tailwind CSS
- Utility-first classes to style triggers and content quickly.
- WAI‑ARIA Authoring Practices — Accordion
- Definitive spec for keyboard and aria behavior expected by assistive tech.
- Practical example on dev.to
- A worked example that inspired this guide and demonstrates Melt UI in the wild.
Conclusion — best practice summary
Use Melt UI with Svelte when you want accessible primitives without losing styling control. Style with Tailwind or your preferred system; add TypeScript for safety. If you need framework-agnostic reuse, consider web components, but expect more plumbing.
Always validate accessibility manually: aria attributes alone don’t guarantee a usable experience. Keyboard flow, focus, and screen reader announcements complete the picture. Ship iteratively: small, tested building blocks beat giant, brittle widgets.
If you want, I can produce a copy-paste SvelteKit route with full TypeScript types, Tailwind config, and tests (axe + Playwright) tailored to your codebase — say the word and I’ll scaffold it.
Semantic core (clustered keywords)
Below is an SEO-minded semantic core derived from your seed keywords, grouped by intent and usage. Use these phrases organically in headings, code comments, alt text, and schema.
{
"primary": [
"svelte collapsible",
"melt-ui collapsible",
"accessible accordion svelte",
"sveltekit accordion",
"tailwindcss accordion"
],
"supporting": [
"collapsible component svelte",
"keyboard accessible accordion",
"wai-aria accordion",
"aria-expanded aria-controls",
"melt ui example",
"headless ui svelte"
],
"related": [
"webcomponents vs svelte",
"typescript svelte components",
"frontend ui-components",
"javascript accordion pattern",
"focus management accordion"
],
"lsi_synonyms": [
"expandable panel",
"toggle panel",
"accordion widget",
"collapse/expand component",
"accessible disclosure"
],
"search_intents": {
"informational": [
"how to make accordion accessible in svelte",
"melt ui collapsible example"
],
"navigational": [
"melt ui docs",
"sveltekit collapsible example"
],
"commercial": [
"best ui components for svelte",
"tailwind accordion component"
]
}
}
Popular user questions (PAA + forum mining)
Collected candidate questions from People Also Ask, some forums, and docs searches. I filtered for relevance to collapsible/accordion implementation with Svelte/Melt UI.
- How to create an accessible accordion in Svelte?
- Does Melt UI handle aria attributes and keyboard interactions?
- Can I style Melt UI primitives with TailwindCSS?
- How to lazy-load heavy content inside a collapsible?
- Should I use Web Components or Svelte components for reusable primitives?
- How to add TypeScript types to Svelte components using Melt UI?
- How does the accordion pattern affect SEO and featured snippets?
Top 3 selected for the FAQ below: questions 1, 2 and 5.
FAQ
- How do I create an accessible accordion in Svelte?
- Use semantic buttons for triggers, ensure
aria-expandedandaria-controlsare synchronized with panel IDs, implement keyboard navigation (Enter/Space, Arrow keys, Home/End), and test with screen readers. Melt UI or similar headless libraries can provide the wiring. - Does Melt UI handle aria attributes and keyboard interactions?
- Yes—Melt UI provides accessibility primitives and keyboard handling for common patterns like collapsibles and accordions. Still inspect the generated DOM and test real assistive tech because implementation details may change across versions.
- When should I choose web components vs Svelte components?
- Choose web components for framework-agnostic reuse across diverse stacks. Choose Svelte components for tighter integration, smaller client bundles, and easier state management in SvelteKit apps. Weigh interop complexity, bundle size, and developer ergonomics.