Skip to content
Gx
GitHub

Accordion

A stack of panels that open one at a time.

<accordion.Accordion>
  <accordion.AccordionItem name="faq" title="Is it accessible?" open>
    Yes. It uses the native details element.
  </accordion.AccordionItem>
  <accordion.AccordionItem name="faq" title="Is it animated?">Yes. The panel height animates.</accordion.AccordionItem>
</accordion.Accordion>

Installation

Run the command in the app module.

Terminal
gx add accordion

The command also installs icons.

The command writes these files.

File Path in the app
Accordion.gx ui/accordion/Accordion.gx
AccordionItem.gx ui/accordion/AccordionItem.gx
Accordion.fixtures.go ui/accordion/Accordion.fixtures.go
AccordionItem.fixtures.go ui/accordion/AccordionItem.fixtures.go

Install icons first.

Copy each file to its path in the app. Change each import of a registry package to the path of that package in the app.

ui/accordion/Accordion.gx
package accordion

props {
  // Class adds classes to the root element.
  Class    string = ""
  // Children is the content of the accordion: the accordion items.
  Children gx.Node
  // Attrs adds HTML attributes to the root element.
  Attrs    gx.Attrs = nil
}

<div class={gx.Cx("w-full", p.Class)} {...p.Attrs}>{p.Children}</div>
ui/accordion/AccordionItem.gx
package accordion

import "github.com/alternayte/gx/registry/icons"

props {
  // Name is the name attribute of the details element.
  // Items with the same name form one accordion, and only one of them is open at a time.
  Name     string
  // Title is the text of the summary, the part that opens and closes the item.
  Title    string
  // Open renders the item open. The default is closed.
  Open     bool = false
  // Disabled stops the summary from opening or closing the item.
  Disabled bool = false
  // Class adds classes to the root element.
  Class    string = ""
  // Children is the content of the item panel.
  Children gx.Node
  // Attrs adds HTML attributes to the root element.
  Attrs    gx.Attrs = nil
}

<details name={p.Name} open={p.Open} class={gx.Cx("group/accordion-item border-border border-b last:border-b-0 [interpolate-size:allow-keywords] [&::details-content]:h-0 [&::details-content]:overflow-hidden [&::details-content]:transition-[height,content-visibility] [&::details-content]:transition-discrete [&::details-content]:duration-200 [&::details-content]:ease-out open:[&::details-content]:h-auto motion-reduce:[&::details-content]:transition-none", p.Class)} {...p.Attrs}>
  <summary inert={p.Disabled} class="flex flex-1 list-none items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 inert:pointer-events-none inert:opacity-50 [&::-webkit-details-marker]:hidden">
    {p.Title}
    <icons.ChevronDown class="pointer-events-none size-4 shrink-0 translate-y-0.5 text-muted-foreground transition-transform duration-200 group-open/accordion-item:rotate-180 motion-reduce:transition-none" />
  </summary>
  <div class="pt-0 pb-4 text-sm">{p.Children}</div>
</details>
ui/accordion/Accordion.fixtures.go
package accordion

import "github.com/alternayte/gx"

var AccordionFixtures = gx.Fixtures[AccordionProps]{
	"Two": {Children: gx.Frag(
		AccordionItem(AccordionItemProps{Name: "faq", Title: "Is it accessible?", Open: true, Children: gx.Text("Yes. It uses the native details element.")}),
		AccordionItem(AccordionItemProps{Name: "faq", Title: "Is it animated?", Children: gx.Text("Yes. The panel height animates.")}),
	)},
}
ui/accordion/AccordionItem.fixtures.go
package accordion

import "github.com/alternayte/gx"

// Each fixture has its own name: details elements that share a name form one
// exclusive group across the whole gallery page.
var AccordionItemFixtures = gx.Fixtures[AccordionItemProps]{
	"Closed":   {Name: "item-closed", Title: "A question", Children: gx.Text("An answer.")},
	"Open":     {Name: "item-open", Title: "A question", Open: true, Children: gx.Text("An answer.")},
	"Disabled": {Name: "item-disabled", Title: "A question", Disabled: true, Children: gx.Text("An answer.")},
}

The theme must define these tokens: --border, --muted-foreground, --ring.

Usage

<accordion.Accordion>
  <accordion.AccordionItem name="faq" title="Is it accessible?">
    Yes. It uses the native details element.
  </accordion.AccordionItem>
</accordion.Accordion>

The accordion uses <details name>, so the browser gives the open and close behaviour. The panel height animates in a browser that supports interpolate-size. Other browsers open the panel at once. Set Disabled to stop an item from opening.

Examples

Accordion: Two

<accordion.Accordion>
  <accordion.AccordionItem name="faq" title="Is it accessible?" open>
    Yes. It uses the native details element.
  </accordion.AccordionItem>
  <accordion.AccordionItem name="faq" title="Is it animated?">Yes. The panel height animates.</accordion.AccordionItem>
</accordion.Accordion>

AccordionItem: Closed

<accordion.AccordionItem name="item-closed" title="A question">An answer.</accordion.AccordionItem>

AccordionItem: Open

<accordion.AccordionItem name="item-open" title="A question" open>An answer.</accordion.AccordionItem>

AccordionItem: Disabled

<accordion.AccordionItem name="item-disabled" title="A question" disabled>An answer.</accordion.AccordionItem>

API reference

A tag sets a prop by its name with a lower-case first letter: Class is class.

accordion.Accordion

Prop Type Default Description
Class string "" Class adds classes to the root element.
Children gx.Node Required Children is the content of the accordion: the accordion items.
Attrs gx.Attrs nil Attrs adds HTML attributes to the root element.

accordion.AccordionItem

Prop Type Default Description
Name string Required Name is the name attribute of the details element. Items with the same name form one accordion, and only one of them is open at a time.
Title string Required Title is the text of the summary, the part that opens and closes the item.
Open bool false Open renders the item open. The default is closed.
Disabled bool false Disabled stops the summary from opening or closing the item.
Class string "" Class adds classes to the root element.
Children gx.Node Required Children is the content of the item panel.
Attrs gx.Attrs nil Attrs adds HTML attributes to the root element.

Do and do not

Do

  • Give every item of one accordion the same Name.
  • Give each accordion on a page its own Name.
  • Put a question in Title and the answer in the body.

Don't

  • Do not use an accordion for primary navigation.
  • Do not open more than one item.

Keyboard

Key Action
Tab Moves focus to the summary.
Enter, Space Opens or closes the item.