Accordion

Accordions are an organized, interactive design pattern of vertically stacked elements, called headers, that toggle the visibility of one or more sections of collapsible content, called panels.

Base accordion

            <div class="max-w-xl mx-auto p-4 text-gray-900 font-sans">
    <ul
        aria-label="Accordion Control Group Buttons"
        class="space-y-4"
        x-data="{ ...accordion() }"
        x-cloak
    >
        <li class="border">
            <h3>
                <button
                    class="text-left w-full flex items-center justify-between py-3 px-4 hover:bg-gray-100 focus:bg-gray-100 focus:outline-none focus:ring focus:ring-blue-500"
                    aria-controls="section-1"
                    x-bind:aria-expanded="isActive('section-1')"
                    x-bind:class="isActiveButtonClasses('section-1')"
                    x-on:click="setActive('section-1')"
                >
                    <span>Commodo Fusce</span>
                    <span aria-hidden="true">
                        <i data-feather="minus" class="w-4 h-4" x-show="isActive('section-1')"></i>
                        <i data-feather="plus" class="w-4 h-4" x-show="!isActive('section-1')"></i>
                    </span>
                </button>
            </h3>
            <div
                id="section-1"
                x-bind:aria-hidden="!isActive('section-1')"
                x-show="isActive('section-1')"
                x-transition:enter="transition-all duration-200"
                x-transition:enter-start="opacity-0 max-h-0 overflow-hidden"
                x-transition:enter-end="opacity-100 max-h-screen"
                x-transition:leave="transition-all duration-100"
                x-transition:leave-start="opacity-100 max-h-screen"
                x-transition:leave-end="opacity-0 max-h-0 overflow-hidden"
                class="h-full overflow-y-auto"
                tabindex="0"
            >
                <div class="px-4 py-8">
                    <h3 class="text-lg font-bold">Fermentum Consectetur</h3>
                    <p class="mt-2 text-sm">Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores harum rem ad veniam quam, ea suscipit nulla ratione et aut dolores sequi eos porro at sed atque quisquam, ipsa quo.</p>
                </div>
            </div>
        </li>
        <li class="border">
            <h3>
                <button
                    aria-controls="section-2"
                    class="text-left w-full flex items-center justify-between py-3 px-4 hover:bg-gray-100 focus:bg-gray-100 focus:outline-none focus:ring focus:ring-blue-500"
                    x-bind:aria-expanded="isActive('section-2')"
                    x-bind:class="isActiveButtonClasses('section-2')"
                    x-on:click="setActive('section-2')"
                >
                    <span>Tortor Condimentum Dapibus</span>
                    <span aria-hidden="true">
                        <i data-feather="minus" class="w-4 h-4" x-show="isActive('section-2')"></i>
                        <i data-feather="plus" class="w-4 h-4" x-show="!isActive('section-2')"></i>
                    </span>
                </button>
            </h3>
            <div
                id="section-2"
                x-bind:aria-hidden="!isActive('section-2')"
                x-show="isActive('section-2')"
                x-transition:enter="transition-all duration-200"
                x-transition:enter-start="opacity-0 max-h-0 overflow-hidden"
                x-transition:enter-end="opacity-100 max-h-screen"
                x-transition:leave="transition-all duration-100"
                x-transition:leave-start="opacity-100 max-h-screen"
                x-transition:leave-end="opacity-0 max-h-0 overflow-hidden"
                class="h-full overflow-y-auto"
                tabindex="0"
            >
                <div class="px-4 py-8">
                    <p class="text-sm">Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores harum rem ad veniam quam, ea suscipit nulla ratione et aut dolores sequi eos porro at sed atque quisquam, ipsa quo.</p>
                </div>
            </div>
        </li>
        <li class="border">
            <h3>
                <button
                    aria-controls="section-3"
                    class="text-left w-full flex items-center justify-between py-3 px-4 hover:bg-gray-100 focus:bg-gray-100 focus:outline-none focus:ring focus:ring-blue-500"
                    x-bind:aria-expanded="isActive('section-3')"
                    x-bind:class="isActiveButtonClasses('section-3')"
                    x-on:click="setActive('section-3')"
                >
                    <span>Fermentum Consectetur Parturient Nibh</span>
                    <span aria-hidden="true">
                        <i data-feather="minus" class="w-4 h-4" x-show="isActive('section-3')"></i>
                        <i data-feather="plus" class="w-4 h-4" x-show="!isActive('section-3')"></i>
                    </span>
                </button>
            </h3>
            <div
                id="section-3"
                x-bind:aria-hidden="!isActive('section-3')"
                x-show="isActive('section-3')"
                x-transition:enter="transition-all duration-200"
                x-transition:enter-start="opacity-0 max-h-0 overflow-hidden"
                x-transition:enter-end="opacity-100 max-h-screen"
                x-transition:leave="transition-all duration-100"
                x-transition:leave-start="opacity-100 max-h-screen"
                x-transition:leave-end="opacity-0 max-h-0 overflow-hidden"
                class="h-full overflow-y-auto"
                tabindex="0"
            >
                <div class="px-4 py-8">
                    <p class="text-sm">Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores harum rem ad veniam quam, ea suscipit nulla ratione et aut dolores sequi eos porro at sed atque quisquam, ipsa quo.</p>
                    <p class="mt-2 text-sm">Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores harum rem ad veniam quam, ea suscipit nulla ratione et aut dolores sequi eos porro at sed atque quisquam, ipsa quo.</p>
                </div>
            </div>
        </li>
    </ul>

</div>

<script>
    const accordion = () => {
        return {
            active: null,

            setActive(section) {
                this.active = this.active === section 
                    ? null 
                    : section
            },

            isActive(section) {
                return this.active === section
            },

            isActiveButtonClasses(section) {
                return { 
                    'bg-gray-200': this.isActive(section),
                }
            },
        }
    }
</script>

        

Base accordion with left icons

            <div class="max-w-xl mx-auto p-4 text-gray-900 font-sans">
    <ul
        aria-label="Accordion Control Group Buttons"
        class="space-y-4"
        x-data="{ ...accordion() }"
        x-cloak
    >
        <li class="border">
            <h3>
                <button
                    aria-controls="section-1"
                    class="w-full flex items-center py-3 px-4 hover:bg-gray-100 focus:bg-gray-100 focus:outline-none focus:ring focus:ring-blue-500"
                    x-bind:aria-expanded="isActive('section-1')"
                    x-bind:class="isActiveButtonClasses('section-1')"
                    x-on:click="setActive('section-1')"
                >
                    <span 
                        class="transition-transform"
                        x-bind:class="isActiveChevronClasses('section-1')"
                    >
                        <i data-feather="chevron-right" class="w-4 h-4"></i>
                    </span>
                    <span class="ml-4">Section 1</span>
                </button>
            </h3>
            <div
                id="section-1"
                x-bind:aria-hidden="!isActive('section-1')"
                x-show="isActive('section-1')"
                x-transition:enter="transition-all duration-200"
                x-transition:enter-start="opacity-0 max-h-0 overflow-hidden"
                x-transition:enter-end="opacity-100 max-h-screen"
                x-transition:leave="transition-all duration-100"
                x-transition:leave-start="opacity-100 max-h-screen"
                x-transition:leave-end="opacity-0 max-h-0 overflow-hidden"
                class="h-full overflow-y-auto"
                tabindex="0"
            >
                <img
                    class="w-full"
                    src="https://images.unsplash.com/photo-1541339907198-e08756dedf3f?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&h=320&q=60"
                    alt="Graduates throwing hats in the air"
                >
                <div class="px-4 py-8">
                    <p class="text-sm">Maecenas sed diam eget risus varius blandit sit amet non magna. Maecenas sed diam eget risus varius blandit sit amet non magna. Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam quis risus eget urna mollis ornare vel eu leo. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
                </div>
            </div>
        </li>
        <li class="border">
            <h3>
                <button
                    aria-controls="section-2"
                    class="w-full flex items-center py-3 px-4 hover:bg-gray-100 focus:bg-gray-100 focus:outline-none focus:ring focus:ring-blue-500"
                    x-bind:aria-expanded="isActive('section-2')"
                    x-bind:class="isActiveButtonClasses('section-2')"
                    x-on:click="setActive('section-2')"
                >
                    <span
                        class="transition-transform"
                        x-bind:class="isActiveChevronClasses('section-2')"
                    >
                        <i data-feather="chevron-right" class="w-4 h-4"></i>
                    </span>
                    <span class="ml-4">Section 2</span>
                </button>
            </h3>
            <div
                id="section-2"
                x-bind:aria-hidden="!isActive('section-2')"
                x-show="isActive('section-2')"
                x-transition:enter="transition-all duration-200"
                x-transition:enter-start="opacity-0 max-h-0 overflow-hidden"
                x-transition:enter-end="opacity-100 max-h-screen"
                x-transition:leave="transition-all duration-100"
                x-transition:leave-start="opacity-100 max-h-screen"
                x-transition:leave-end="opacity-0 max-h-0 overflow-hidden"
                class="h-full overflow-y-auto"
                tabindex="0"
            >
                <div class="px-4 py-8">
                    <p class="text-sm">Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores harum rem ad veniam quam, ea suscipit nulla ratione et aut dolores sequi eos porro at sed atque quisquam, ipsa quo.</p>
                </div>
            </div>
        </li>
        <li class="border">
            <h3>
                <button
                    aria-controls="section-3"
                    class="w-full flex items-center py-3 px-4 hover:bg-gray-100 focus:bg-gray-100 focus:outline-none focus:ring focus:ring-blue-500"
                    x-bind:aria-expanded="isActive('section-3')"
                    x-bind:class="isActiveButtonClasses('section-3')"
                    x-on:click="setActive('section-3')"
                >
                    <span
                        class="transition-transform"
                        x-bind:class="isActiveChevronClasses('section-3')"
                    >
                        <i data-feather="chevron-right" class="w-4 h-4"></i>
                    </span>
                    <span class="ml-4">Section 3</span>
                </button>
            </h3>
            <div
                id="section-3"
                x-bind:aria-hidden="!isActive('section-3')"
                x-show="isActive('section-3')"
                x-transition:enter="transition-all duration-200"
                x-transition:enter-start="opacity-0 max-h-0 overflow-hidden"
                x-transition:enter-end="opacity-100 max-h-screen"
                x-transition:leave="transition-all duration-100"
                x-transition:leave-start="opacity-100 max-h-screen"
                x-transition:leave-end="opacity-0 max-h-0 overflow-hidden"
                class="h-full overflow-y-auto"
                tabindex="0"
            >
                <div class="px-4 py-8">
                    <p class="text-sm">Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores harum rem ad veniam quam, ea suscipit nulla ratione et aut dolores sequi eos porro at sed atque quisquam, ipsa quo.</p>
                    <p class="mt-2 text-sm">Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores harum rem ad veniam quam, ea suscipit nulla ratione et aut dolores sequi eos porro at sed atque quisquam, ipsa quo.</p>
                </div>
            </div>
        </li>
    </ul>
</div>

<script>
    const accordion = () => {
        return {
            active: null,

            setActive(section) {
                this.active = this.active === section 
                    ? null 
                    : section
            },

            isActive(section) {
                return this.active === section
            },

            isActiveButtonClasses(section) {
                return { 
                    'bg-gray-200': this.isActive(section),
                }
            },

            isActiveChevronClasses(section) {
                return { 
                    'transform rotate-90': this.isActive(section),
                }
            }
        }
    }
</script>

        

Nested accordion

            <div class="max-w-xl mx-auto p-4 text-gray-900 font-sans">
    <ul
        aria-label="Accordion Control Group Buttons"
        class="space-y-4"
        x-data="{ ...parentAccordion() }"
        x-cloak
    >
        <li
            class="border-b-2"
            x-bind:class="isActiveLiClasses('section-1')"            
        >
            <h3>
                <button
                    class="w-full flex items-center justify-between py-3 px-4 border border-gray-200 hover:bg-gray-100 focus:outline-none focus:ring focus:ring-blue-500"
                    aria-controls="section-1"
                    x-bind:aria-expanded="isActive('section-1')"
                    x-bind:class="isActiveButtonClasses('section-1')"
                    x-on:click="setActive('section-1')"
                >
                    <span>Section 1</span>
                    <span aria-hidden="true" class="ml-2">
                        <i data-feather="minus" class="w-4 h-4" x-show="isActive('section-1')"></i>
                        <i data-feather="plus" class="w-4 h-4" x-show="!isActive('section-1')"></i>
                    </span>
                </button>
            </h3>
            <div
                id="section-1"
                x-bind:aria-hidden="!isActive('section-1')"
                x-show="isActive('section-1')"
                x-transition:enter="transition-all duration-200"
                x-transition:enter-start="opacity-0 max-h-0 overflow-hidden"
                x-transition:enter-end="opacity-100 max-h-screen"
                x-transition:leave="transition-all duration-100"
                x-transition:leave-start="opacity-100 max-h-screen"
                x-transition:leave-end="opacity-0 max-h-0 overflow-hidden"
                class="h-full overflow-y-auto"
                tabindex="0"
            >
                <div class="px-2 py-4">
                    <ul
                        x-data="{ ...childAccordion() }"
                        aria-label="Accordion Control Group Buttons"
                    >
                        <li>
                            <h4>
                                <button
                                    class="w-full flex items-center justify-between py-3 px-2 focus:outline-none focus:ring focus:ring-blue-500"
                                    aria-controls="section-1-child-1"
                                    x-bind:aria-expanded="isActive('section-1-child-1')"
                                    x-on:click="setActive('section-1-child-1')"
                                >
                                    <span>Child 1</span>
                                    <span aria-hidden="true" class="ml-2">
                                        <i data-feather="minus" class="w-4 h-4" x-show="isActive('section-1-child-1')"></i>
                                        <i data-feather="plus" class="w-4 h-4" x-show="!isActive('section-1-child-1')"></i>
                                    </span>
                                </button>
                            </h4>
                            <div
                                id="section-1-child-1"
                                x-bind:aria-hidden="!isActive('section-1-child-1')"
                                x-show="isActive('section-1-child-1')"
                                x-transition:enter="transition-all duration-200"
                                x-transition:enter-start="opacity-0 max-h-0 overflow-hidden"
                                x-transition:enter-end="opacity-100 max-h-screen"
                                x-transition:leave="transition-all duration-100"
                                x-transition:leave-start="opacity-100 max-h-screen"
                                x-transition:leave-end="opacity-0 max-h-0 overflow-hidden"
                                class="h-full overflow-y-auto"
                                tabindex="0"
                            >
                                <div class="pt-2 px-2 pb-4">
                                    <p class="text-sm">Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores harum rem ad veniam quam, ea suscipit nulla ratione et aut dolores sequi eos porro at sed atque quisquam, ipsa quo.</p>
                                    <p class="mt-2 text-sm">Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores harum rem ad veniam quam, ea suscipit nulla ratione et aut dolores sequi eos porro at sed atque quisquam, ipsa quo.</p>
                                </div>
                            </div>
                        </li>
                        <li>
                            <h4>
                                <button
                                    class="w-full flex items-center justify-between py-3 px-2 focus:outline-none focus:ring focus:ring-blue-500"
                                    aria-controls="section-1-child-2"
                                    x-bind:aria-expanded="isActive('section-1-child-2')"
                                    x-on:click="setActive('section-1-child-2')"
                                >
                                    <span>Child 2</span>
                                    <span aria-hidden="true" class="ml-2">
                                        <i data-feather="minus" class="w-4 h-4" x-show="isActive('section-1-child-2')"></i>
                                        <i data-feather="plus" class="w-4 h-4" x-show="!isActive('section-1-child-2')"></i>
                                    </span>
                                </button>
                            </h4>
                            <div
                                id="section-1-child-2"
                                x-bind:aria-hidden="!isActive('section-1-child-2')"
                                x-show="isActive('section-1-child-2')"
                                x-transition:enter="transition-all duration-200"
                                x-transition:enter-start="opacity-0 max-h-0 overflow-hidden"
                                x-transition:enter-end="opacity-100 max-h-screen"
                                x-transition:leave="transition-all duration-100"
                                x-transition:leave-start="opacity-100 max-h-screen"
                                x-transition:leave-end="opacity-0 max-h-0 overflow-hidden"
                                class="h-full overflow-y-auto"
                                tabindex="0"
                            >
                                <div class="pt-2 px-2 pb-4">
                                    <p class="text-sm">Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores harum rem ad veniam quam, ea suscipit nulla ratione et aut dolores sequi eos porro at sed atque quisquam, ipsa quo.</p>
                                </div>
                            </div>
                        </li>
                    </ul>
                </div>
            </div>
        </li>
        <li
            class="border-b-2"
            x-bind:class="isActiveLiClasses('section-2')"
        >
            <h3>
                <button
                    class="w-full flex items-center justify-between py-3 px-4 border border-gray-200 hover:bg-gray-100 focus:outline-none focus:ring focus:ring-blue-500"
                    aria-controls="section-2"
                    x-bind:aria-expanded="isActive('section-2')"
                    x-bind:class="isActiveButtonClasses('section-2')"
                    x-on:click="setActive('section-2')"
                >
                    <span>Section 2</span>
                    <span aria-hidden="true" class="ml-2">
                        <i data-feather="minus" class="w-4 h-4" x-show="isActive('section-2')"></i>
                        <i data-feather="plus" class="w-4 h-4" x-show="!isActive('section-2')"></i>
                    </span>
                </button>
            </h3>
            <div
                id="section-2"
                x-bind:aria-hidden="!isActive('section-2')"
                x-show="isActive('section-2')"
                x-transition:enter="transition-all duration-200"
                x-transition:enter-start="opacity-0 max-h-0 overflow-hidden"
                x-transition:enter-end="opacity-100 max-h-screen"
                x-transition:leave="transition-all duration-100"
                x-transition:leave-start="opacity-100 max-h-screen"
                x-transition:leave-end="opacity-0 max-h-0 overflow-hidden"
                class="h-full overflow-y-auto"
                tabindex="0"
            >
                <div class="px-2 py-4">
                    <ul
                        x-data="{ ...childAccordion() }"
                        aria-label="Accordion Control Group Buttons"
                    >
                        <li>
                            <h4>
                                <button
                                    class="w-full flex items-center justify-between py-3 px-2 focus:outline-none focus:ring focus:ring-blue-500"
                                    aria-controls="section-2-child-1"
                                    x-bind:aria-expanded="isActive('section-2-child-1')"
                                    x-on:click="setActive('section-2-child-1')"
                                >
                                    <span>Child 1</span>
                                    <span aria-hidden="true" class="ml-2">
                                        <i data-feather="minus" class="w-4 h-4" x-show="isActive('section-2-child-1')"></i>
                                        <i data-feather="plus" class="w-4 h-4" x-show="!isActive('section-2-child-1')"></i>
                                    </span>
                                </button>
                            </h4>
                            <div
                                id="section-2-child-1"
                                x-bind:aria-hidden="!isActive('section-2-child-1')"
                                x-show="isActive('section-2-child-1')"
                                x-transition:enter="transition-all duration-200"
                                x-transition:enter-start="opacity-0 max-h-0 overflow-hidden"
                                x-transition:enter-end="opacity-100 max-h-screen"
                                x-transition:leave="transition-all duration-100"
                                x-transition:leave-start="opacity-100 max-h-screen"
                                x-transition:leave-end="opacity-0 max-h-0 overflow-hidden"
                                class="h-full overflow-y-auto"
                                tabindex="0"
                            >
                                <div class="pt-2 px-2 pb-4">
                                    <p class="text-sm">Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores harum rem ad veniam quam, ea suscipit nulla ratione et aut dolores sequi eos porro at sed atque quisquam, ipsa quo.</p>
                                    <p class="mt-2 text-sm">Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores harum rem ad veniam quam, ea suscipit nulla ratione et aut dolores sequi eos porro at sed atque quisquam, ipsa quo.</p>
                                </div>
                            </div>
                        </li>
                        <li>
                            <h4>
                                <button
                                    class="w-full flex items-center justify-between py-3 px-2 focus:outline-none focus:ring focus:ring-blue-500"
                                    aria-controls="section-2-child-2"
                                    x-bind:aria-expanded="isActive('section-2-child-2')"
                                    x-on:click="setActive('section-2-child-2')"
                                >
                                    <span>Child 2</span>
                                    <span aria-hidden="true" class="ml-2">
                                        <i data-feather="minus" x-show="isActive('section-2-child-2')" class="w-4 h-4"></i>
                                        <i data-feather="plus" x-show="!isActive('section-2-child-2')" class="w-4 h-4"></i>
                                    </span>
                                </button>
                            </h4>
                            <div
                                id="section-2-child-2"
                                x-bind:aria-hidden="!isActive('section-2-child-2')"
                                x-show="isActive('section-2-child-2')"
                                x-transition:enter="transition-all duration-200"
                                x-transition:enter-start="opacity-0 max-h-0 overflow-hidden"
                                x-transition:enter-end="opacity-100 max-h-screen"
                                x-transition:leave="transition-all duration-100"
                                x-transition:leave-start="opacity-100 max-h-screen"
                                x-transition:leave-end="opacity-0 max-h-0 overflow-hidden"
                                class="h-full overflow-y-auto"
                                tabindex="0"
                            >
                                <div class="pt-2 px-2 pb-4">
                                    <p class="text-sm">Lorem ipsum dolor sit amet consectetur adipisicing elit. Asperiores harum rem ad veniam quam, ea suscipit nulla ratione et aut dolores sequi eos porro at sed atque quisquam, ipsa quo.</p>
                                </div>
                            </div>
                        </li>
                    </ul>
                </div>
            </div>
        </li>
    </ul>
</div>

<script>
    const baseAccordion = () => {
        return {
            active: null,

            setActive(section) {
                this.active = this.active === section 
                    ? null 
                    : section
            },

            isActive(section) {
                return this.active === section
            },
        }
    }

    const parentAccordion = () => {
        return {
            ...baseAccordion(),

            isActiveLiClasses(section) {
                return {
                   'border-gray-200': this.isActive(section),
                   'border-transparent': !this.isActive(section),
                }
            },

            isActiveButtonClasses(section) {
                return {
                   'bg-gray-200': this.isActive(section)
                }
            }
        }
    }

    const childAccordion = () => {
        return {
            ...baseAccordion(),
        }
    }
</script>

        

Use Cases

  • When users need quick access to only relevant sections of content on the page. (age related health information, doctors by specialty, tax laws by state)
  • When there is a large amount of content and a limited amount of space. (star wars memorabilia by movie)
  • When too much content at once could overwhelm the user. (college course descriptions by school, by major; wine varietals by grape, by county)
  • When consolidating content on a single page would be more effective than linking to content on multiple pages. (Employee contact info by department)
  • When the length of the page’s content requires excessive scrolling. (Passport Visa form, medical history)
  • When the number of options the user can click are few. (Hotel rooms: economy, standard, deluxe, suite)
  • When the content and its categories are well established and familiar. (Menu: breakfast, lunch, dinner, dessert)
  • When printing the accordion’s content is not a primary concern.

Accessibility Requirements

Make entire header selectable

A larger target area makes selection easier for mobile and limited dexterity users.

Use Semantic Mark-up

Wrap the <button> element inside the header’s h tag to allow keyboards to interact with the accordion. Headings make finding content on the page easy for both sighted users and screen readers. They also make sense semantically by providing clear titles for content they disclose.

Note: Using non-semantic elements such as <div>, <span> and <li> with role=”button will result in a loss of accessibility features. Nesting headings inside of non-semantic tags overrides the heading semantics, which are relied on by screen readers as navigational aids. Nor do they possess the essential browser behaviors, like focus, or the bindings for control activation, and will require custom coding to duplicate that functionality, that’s already built into the <button>.

Create Relationships Between each Header and its Panel

Set an aria-controls attribute in the header button to the ID of its content panel. This creates an unambiguous programmatic association between the elements that screen readers can detect.

Provide Focus Indication

Style the selected header button to be visually distinct from the other buttons. This indicates to users that it’s an element that performs an action. Choose easily perceptible color changes to indicate focus. Subtle colors may not be seen by low vision users. Focus indication should be applied to the entire button, not just a small change to down arrow or a plus symbol, which may go unnoticed.

Provide Focus Control

Provide keyboard access to the panel content by making it focusable. Since panel content isn’t a natively focusable, adding the tabindex=”0” attribute to the panel container includes it in the page’s tab order directly after its header. This is especially helpful when a panels contains no focusable element in its contents.

Keyboard Guidelines

Tab Expands and collapses the panel content of the header that has focus.
Space/Enter Expands and collapses the panel content of the header that has focus.
Shift + Tab Shifts focus to the previous focusable element.
Down Arrow (optional) When focus is on a header, moves focus to the next header.
When the last header has focus, move focus back to first header.
Up Arrow (optional) When focus is on a header, moves focus to the previous header.
When the first header has focus, move focus back to last header.
Home (optional) When focus is on a header, moves focus to first header.
End (optional) When focus is on a header, Moves focus to last header.