thc-accordion-context-api Svelte Themes

Thc Accordion Context Api

A fully accessible, animated accordion component built with Svelte 5 using the Context API and the Compound Component pattern

Svelte 5 Accordion – Compound Components with Context API

A fully accessible, animated accordion component built with Svelte 5 using the Context API and the Compound Component pattern.

Overview

This project demonstrates how to build reusable, composable UI components in Svelte 5 using the Compound Component pattern. Instead of passing configuration through props, compound components share implicit state through Svelte's Context API, enabling a clean and flexible API.

Features

  • Svelte 5 Context API – Uses setContext and getContext for clean state sharing
  • Compound Component Pattern – Composable API with Accordion, AccordionItem, AccordionTrigger, and AccordionContent
  • Single/Multi Mode – Toggle between allowing one or multiple items open
  • Fully Accessible – ARIA attributes and keyboard navigation out of the box
  • Smooth Animations – CSS grid-based expand/collapse transitions
  • TypeScript – Fully typed with interfaces for context and options

Component Structure

Accordion/
├── Accordion.svelte           # Root component, provides context
├── AccordionItem.svelte       # Container for each item
├── AccordionTrigger.svelte    # Clickable header/button
├── AccordionContent.svelte    # Collapsible content panel
├── accordion-context.svelte.ts # Context creation and retrieval
├── types.ts                   # TypeScript interfaces
└── index.ts                   # Public exports

Usage

<script>
    import {
        Accordion,
        AccordionContent,
        AccordionItem,
        AccordionTrigger
    } from '$lib/components/accordion';
</script>

<Accordion single defaultExpanded={['item-1']}>
    <AccordionItem id="item-1">
        <AccordionTrigger itemId="item-1">What is your return policy?</AccordionTrigger>
        <AccordionContent itemId="item-1">
            <p>We offer a 30-day return policy for all unused items.</p>
        </AccordionContent>
    </AccordionItem>

    <AccordionItem id="item-2">
        <AccordionTrigger itemId="item-2">How long does shipping take?</AccordionTrigger>
        <AccordionContent itemId="item-2">
            <p>Standard shipping takes 5-7 business days.</p>
        </AccordionContent>
    </AccordionItem>
</Accordion>

Props

<Accordion>

Prop Type Default Description
single boolean false Only allow one item open at a time
defaultExpanded string[] [] Initially expanded item IDs
onExpandedChange (ids: string[]) => void Callback when expanded items change
class string '' Additional CSS class

<AccordionItem>

Prop Type Description
id string Unique identifier for this item
class string Additional CSS class

<AccordionTrigger> / <AccordionContent>

Prop Type Description
itemId string ID of the accordion item this belongs to
class string Additional CSS class

How the Context API Works

The accordion uses Svelte 5's Context API to share state between components without prop drilling:

// accordion-context.svelte.ts
import { setContext, getContext } from 'svelte';
import { SvelteSet } from 'svelte/reactivity';

const ACCORDION_KEY = Symbol('accordion');

export function createAccordionContext(options) {
    const expandedIds = new SvelteSet(options.defaultExpanded);

    const context = {
        expandedIds,
        toggle(id) {
            /* ... */
        },
        isExpanded(id) {
            return expandedIds.has(id);
        }
        // ...
    };

    return setContext(ACCORDION_KEY, context);
}

export function getAccordionContext() {
    return getContext(ACCORDION_KEY);
}

Child components retrieve the context and react to state changes:

// In AccordionTrigger.svelte
const accordion = getAccordionContext();
let isExpanded = $derived(accordion.isExpanded(itemId));

Getting Started

Install dependencies

pnpm install

Start development server

pnpm dev

Build for production

pnpm build

Acknowledgments

  • Built as a companion demo for The Hackpile Chronicles article series on Svelte 5 Context API and Compound Components
  • Uses the excellent Lucide icons

Made with ❤️ using Svelte 5, SvelteKit, and TypeScript

Learn More

License

MIT

Top categories

Loading Svelte Themes