Accordion

A vertically stacked set of interactive headings that each reveal a section of content.

Yes. It adheres to the WAI-ARIA design pattern.

Yes. It comes with default styles that match the other components' aesthetic.

Yes. It's animated by default, but you can disable it if you prefer.

package showcase

import "github.com/axzilla/goilerplate/pkg/components"

templ AccordionShowcase() {
	<div class="flex justify-center items-center border rounded-md py-16 px-4">
		@components.Accordion(components.AccordionProps{
			Items: []components.AccordionItem{
				{
					ID:      "item-1",
					Trigger: templ.Raw("Is it accessible?"),
					Content: templ.Raw("Yes. It adheres to the WAI-ARIA design pattern."),
				},
				{
					ID:      "item-2",
					Trigger: templ.Raw("Is it styled?"),
					Content: templ.Raw("Yes. It comes with default styles that match the other components' aesthetic."),
				},
				{
					ID:      "item-3",
					Trigger: templ.Raw("Is it animated?"),
					Content: templ.Raw("Yes. It's animated by default, but you can disable it if you prefer."),
				},
			},
			Class: "w-full sm:max-w-[70%]",
		})
	</div>
}
package components

import (
	"github.com/axzilla/goilerplate/pkg/icons"
	"github.com/axzilla/goilerplate/pkg/utils"
)

type AccordionItem struct {
	// ID is the unique identifier for managing accordion item state
	ID string

	// Trigger is the content shown in the header/trigger area
	// Can be any templ.Component (typically text)
	Trigger templ.Component

	// Content is the expandable content section
	// Can be any templ.Component
	Content templ.Component
}

type AccordionProps struct {
	// Items contains the accordion sections
	Items []AccordionItem

	// Class adds custom CSS classes
	Class string

	// Attributes for additional HTML attributes and Alpine.js bindings
	Attributes templ.Attributes
}

// Accordion renders a collapsible content section component with expand/collapse functionality.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/accordion
//
// Props:
// - Items: Array of accordion sections with ID, trigger and content
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes (e.g. data-testid)
templ Accordion(props AccordionProps) {
	<div
		x-data="{ 
			activeItem: null,
			toggleItem(itemId) {
				this.activeItem = this.activeItem === itemId ? null : itemId;
			}
		}"
		class={ utils.TwMerge("divide-y divide-border rounded-md border", props.Class) }
		{ props.Attributes... }
	>
		for _, item := range props.Items {
			<div class="group">
				<h3>
					<button
						type="button"
						@click={ "toggleItem('" + item.ID + "')" }
						class="flex w-full items-center justify-between py-4 px-5 text-left font-medium transition-all hover:underline [&[aria-expanded=true]>svg]:rotate-180"
						:aria-expanded={ "activeItem === '" + item.ID + "'" }
					>
						@item.Trigger
						@icons.ChevronDown(icons.IconProps{Size: "16"})
					</button>
				</h3>
				<div
					x-show={ "activeItem === '" + item.ID + "'" }
					x-collapse
					x-cloak
					class="px-5 pb-4 pt-0"
				>
					@item.Content
				</div>
			</div>
		}
	</div>
}