# Accordion An expand/collapse panel list — like a FAQ section or a step-by-step guide where the user reveals each answer one at a time. --- ## Quick example ```csharp new Accordion( id: "faq", items: new[] { ("What is this?", "A fast HTMX app framework."), ("Is it AOT-safe?", "Yes, fully."), ("Do I need Node?", "Only for the Tailwind build step."), }) ``` That's it. Drop this into a page slot and you have a working FAQ section. --- ## All the options ```csharp public Accordion( string id, IEnumerable<(string Title, string Content)> items, int openIndex = -1) ``` | Parameter | What it does | |---|---| | `id` | A unique identifier for this accordion on the page. If you have two accordions on the same page, they need different ids. | | `items` | The list of panels. Each item is a pair: the header text (`Title`) and the body content (`Content`). | | `openIndex` | Which panel should start open. `0` = first panel, `1` = second, `-1` = all closed (default). | --- ## Real-world examples ### FAQ page with the first item pre-opened ```csharp new Accordion( id: "faq", items: new[] { ("How do I reset my password?", "Go to Settings → Security → Reset Password."), ("How do I cancel my account?", "Contact support from the Help page."), ("Where are my invoices?", "Under Billing in your account dashboard."), }, openIndex: 0) // first answer visible on load ``` ### Step-by-step guide with HTML content inside items Item `Content` is rendered as raw HTML, so you can use markup inside it: ```csharp new Accordion( id: "setup-guide", items: new[] { ("Step 1 — Install dependencies", "Run npm install inside the Htmx.ApiDemo folder."), ("Step 2 — Start MongoDB", "

Start the MongoDB service, then confirm it is running on localhost:27017.

"), ("Step 3 — Run the app", "Run dotnet run --project Htmx.ApiDemo and open http://localhost:5120."), }, openIndex: 0) ``` > **Important:** `Title` and `Content` are inserted as raw HTML. If either value comes from user input or a database, HTML-encode it first: > ```csharp > System.Web.HttpUtility.HtmlEncode(userTitle) > ``` ### Inside a page ```html

Frequently Asked Questions

$$FaqAccordion$$
``` ```csharp // Templates/FaqPage.htmx.cs public sealed class FaqPage : FaqPageBase { private readonly IHtmxComponent _faqAccordion; public FaqPage() { _faqAccordion = new Components.Accordion( id: "faq", items: new[] { ("What is BeepBoop?", "A fast, AOT-safe HTMX web framework built on .NET 10."), ("Do I need Node.js?", "Only to run the Tailwind CSS build step."), ("Is MongoDB required?", "No — swap in any data store you prefer."), }); } protected override void RenderFaqAccordion(HtmxRenderContext ctx) => _faqAccordion.Render(ctx.Next()); } ``` --- ## How it works The server renders all panels into the HTML. Closed panels are given `height: 0; opacity: 0` inline styles so they are invisible immediately — no layout flash. The JavaScript in `components.js` (`initAccordion`) then attaches click listeners. When a panel is opened, JS reads the panel's `scrollHeight` (its natural height) and animates the inline `height` from `0` to that value alongside the opacity, giving a smooth slide-down. The chevron icon rotates 180° to point down when open. If the page content is updated by HTMX, `htmx:afterSwap` re-runs the initialisation so newly swapped-in accordions also get click behaviour. Users can open multiple panels simultaneously — there is no "only one open at a time" constraint. --- ## Tips - The `id` must be unique if you place more than one accordion on a page. - `openIndex` only controls the initial server-rendered state — the user can freely open or close any panel after that. - To listen for accordion interactions from another script, add a `click` listener to the parent container and check `event.target.closest('.accordion-trigger')`. ("How do I deploy?", "Run dotnet publish -c Release for a native AOT binary."), }); } protected override void RenderFaqAccordion(HtmxRenderContext ctx) => _faq.Render(ctx.Next()); } ``` **`Templates/FaqPage.htmx.cs` — GET handler** ```csharp [Handler] [MapGet("/faq")] public static partial class GetFaqHandler { public record Query(); private static Task HandleAsync( Query _, HttpContext ctx, CancellationToken ct) => ctx.WriteHtmxPage(new FaqPage(), title: "FAQ"); } ```