Accordion

Om komponenten

Accordion er en komponent som lar brukeren åpne og lukke innhold.

Vi har valgt å bruke de semantiske details og summary-taggene for å lage en accordion. Dette er en enkel og semantisk måte å lage en accordion på da tastaturnavigering skjer sømløst. Det finnes ulike måter å lage en Accordion på, og du kan lese mer om avgjørelsen under universell utforming”-fanen.

For å bruke Punkt sin Accordion komponent kan man bruke <PktAccordion> som en wrapper rundt flere <PktAccordionItem> eller <AccordionItem> som en standalone komponent (dersom man kun trenger én AccordionItem). Som standard, vil man kunne ha flere åpne rader i Punkt sin Accordion samtidig. Per dags dato, er det opptil bruker å begrense antall åpne rader selv i sin løsning om dette er ønsket funksjonalitet. (Les mer under “Begrens antall åpne rader”)

Ofte stilte spørsmål

<h2 id="accordion-heading-1">Borderless</h2>
<div
  data-testid="pkt-accordion"
  class="pkt-accordion pkt-accordion--borderless"
  aria-labelledby="accordion-heading-1"
>
  <details
    aria-controls="pkt-accordion-item-content-1"
    class="pkt-accordion-item"
    id="pkt-accordion-item-header-1"
  >
    <summary
      aria-labelledby="pkt-accordion-item-header-1"
      class="pkt-accordion-item__title"
      id="pkt-accordion-item-summary-1"
    >
      Item summary 1
      <span class="pkt-icon pkt-accordion-item__icon">
        <svg viewBox="0 0 32 32" aria-hidden="true">
          <use href="#chevron-thin-down"></use>
        </svg>
      </span>
    </summary>
    <div
      id="pkt-accordion-item-content-1"
      role="region"
      class="pkt-accordion-item__content"
    >
      Item Content 1
    </div>
  </details>
  <details
    aria-controls="pkt-accordion-item-content-2"
    class="pkt-accordion-item"
    id="pkt-accordion-item-header-2"
  >
    <summary
      aria-labelledby="pkt-accordion-item-header-2"
      class="pkt-accordion-item__title"
      id="pkt-accordion-item-summary-2"
    >
      Item summary 1
      <span class="pkt-icon pkt-accordion-item__icon">
        <svg viewBox="0 0 32 32" aria-hidden="true">
          <use href="#chevron-thin-down"></use>
        </svg>
      </span>
    </summary>
    <div
      id="pkt-accordion-item-content-1"
      role="region"
      class="pkt-accordion-item__content"
    >
      Item Content 1
    </div>
  </details>
</div>
  <pkt-accordion key="acc"  :compact="false" skin="borderless">
    <pkt-accordion-item
      v-for="item in accordionItems"
      :key="item.id"
      :id="item.id"
      :title="item.title"
      :toggleProps="{ isOpen: openedItem === item.id, onToggleClick: toggleCurrentOpenItem }"
    >
      {{ item.content }}
    </pkt-accordion-item>
  </pkt-accordion>
<PktAccordion compact={false} skin="blue">
  {accordionItems.map((item, index) => (
    <PktAccordionItem id={item.id} key={item.id} title={item.title}>
      {item.content}
    </PktAccordionItem>
  ))}
</PktAccordion>

Avhengigheter

Ikoner:

  • chevron-thin-down

Begrens antall åpne rader

Som standard, støtter Accordion åpning av flere rader samtidig. For å styre at kun én rad kan være åpen om gangen, må man styre alle radene sin toggle tilstand lokalt - det vil si at man må overstyre den automatiske tilstandshåndteringen til komponenten. Dette gjøres ved å sette en boolean isOpen og en onClick/click funksjon på <AccordionItem>/<pkt-accordion-item> som styrer åpne-lukke tilstanden til komponenten`.

I React, trenger man å sende inn event for å forhindre inkonsistent oppførsel. Dette er fordi <details>-elementet har sin egen innebygde toggle-funksjon som kan føre til ikonsistens når vi prøver å sette isOpen-propen i React. I <AccordionItem> kjører vi e.preventDefault() for å forhindre at <details>-elementet sin innebygde toggle-funksjon kjører. Sjekk eksemplene under!

// Elements
<script>
  @state() private openedItem: string = ''

function toggleCurrentOpenItem(e: MouseEvent, id: string) {
e.preventDefault() // Prevent default behavior to ensure controlled state
if (this.openedItem === id) {
this.openedItem = ''
} else {
this.openedItem = id
}
}

</script>

<pkt-accordion skin="blue" aria-labelledby="accordion-standard">
  <pkt-accordion-item
    id=${item.id}
    title=${item.title}
    .isOpen=${this.openedItem == item.id}
    @click=${(e: MouseEvent) => this.toggleCurrentOpenItem(e, item.id)}
    >
    ${item.content}
    <p>Element innhold</p>
  </pkt-accordion-item>`
</pkt-accordion>
  <template>
    <pkt-accordion key="acc"  :compact="false" skin="borderless">
      <pkt-accordion-item
        v-for="item in accordionItems"
        :key="item.id"
        :id="item.id"
        :title="item.title"
        :isOpen="openedItem === item.id"
        @click="toggleCurrentOpenItem(item.id)"
      >
        {{ item.content }}
      </pkt-accordion-item>
    </pkt-accordion>
  </template>
  <script>
      const toggleCurrentOpenItem = (id: string) => {
        openedItem.value = openedItem.value === id ? '' : id
      }
  </script>
const [openedItem, setOpenedItem] = useState<string>('')

const toggleCurrentOpenItem = (e: React.MouseEvent, id: string) => {
  if (openedItem.includes(id)) {
    setOpenedItem('')
  } else {
    setOpenedItem(id)
  }
}

return (
  <>
    <h3 id="heading-accordion">Heading</h3>
    <PktAccordion compact skin={'borderless'} aria-labelledby="heading-accordion">
      {accordionItems.map((item, index) => {
        return (
          <PktAccordionItem
              id={item.id}
              key={item.id}
              title={item.title}
              defaultOpen={index === 0}
              isOpen={openedItem === item.id}
              onClick={(e) => toggleCurrentOpenItem(e, item.id)} >
              {item.content}
          </PktAccordionItem>
        )
      })}
    </PktAccordion>
  </>
)

Varianter

Accordion har fire ulike skins:

  • borderless (standard)
  • outlined
  • beige
  • blue

Accordion kommer også i en compact versjon. Som standard, er compactsatt til false.

Bruk av enkel <AccordionItem>

AccordionItem kan brukes som en standalone komponent.Ønsker man annen styling enn standard, kan man sette skin og compact direkte på <AccordionItem>. Bruker man <PktAccordion> som wrapper, setter man skin og compact direkte på <PktAccordion> for konsekvent styling.

// React
<AccordionItem skin="blue" compact title="Tittel">
  <p>Innholdet i AccordionItem</p>
</AccordionItem>

// Elements
<pkt-accordion-item skin="blue" compact title="Tittel">
  <p>Innholdet i AccordionItem</p>
</pkt-accordion-item>

CSS oversikt

I Punkt brukes BEM-styling. Under er Accordion sin CSS-struktur.

Block:

  • .pkt-accordion
  • .pkt-accordion-item

Elements:

  • .pkt-accordion-item__title
  • .pkt-accordion-item__icon
  • .pkt-accordion-item__content

Modifiers:

  • .pkt-accordion--borderless
  • .pkt-accordion--outlined
  • .pkt-accordion--beige
  • .pkt-accordion--blue
  • .pkt-accordion-item--open

Props og slots

<Accordion/>

PropsTypeValidationDefaultDescription
classNamestringStyling klasse
childrenReactNode eller ReactNode[]<Accordion> må wrappe rundt <AccordionItem>
compactbooleanfalseMindre padding og tekststørrelse
skinborderless, outlined, beige, blueborderlessHvert skin har en egen bakgrunnsfarge og borderfarge

<AccordionItem/>

PropsTypeValidationDefaultDescription
idstringPåkrevdSettes til en unik id per item for å koble item-header med item-content slik at skjermlesere leser opp innhold korrekt
titlestring PåkrevdEn tittel/oppsummering av innholdet i <AccordionItem>
defaultOpenboolean -falseSett til true dersom man ønsker å la spesifikk <AccordionItem> være åpen når man først laster inn siden
refLegacyRef<HTMLDivElement>-Tillater å hente en ref til komponent instansen.
classNamestring-Styling klasse
childrenReactNode eller ReactNode[]-<Accordion> må wrappe rundt <AccordionItem>
skinborderless, outlined, beige, blue-borderlessHvert skin har en egen bakgrunnsfarge og borderfarge. Settes kun dersom <AccordionItem> brukes alene.
compactboolean-falseGir en kompakt versjon av <AccordionItem>. Settes kun dersom <AccordionItem> brukes alene.
isOpenboolean-falseKontrollerer åpen-lukk tilstanden til <AccordionItem>. Overstyrer automatisk åpne-lukk funksjonalitet.
onClick(e: MouseEvent) => void-En CallBack funksjon som kjører når <AccordionItem> blir klikket på.

Hvordan ta i bruk?

// React
import { PktAccordion, PktAccordionItem } from "@oslokommune/punkt-react";

// Custom Element:
import "@oslokommune/punkt-elements/dist/pkt-accordion.js";
import "@oslokommune/punkt-elements/dist/pkt-accordion-item.js";

// Custom Element fra CDN:
<script src="https://punkt-cdn.oslo.kommune.no/latest/elements/pkt-accordion.js"></script>;
<script src="https://punkt-cdn.oslo.kommune.no/latest/elements/pkt-accordion-item.js"></script>;