Tabs

Om komponenten

Tabs er i utgangspunktet ment å brukes til å erstatte innhold i et begrenset område under fanerekken, uten å navigere vekk fra siden, men i enkelte tilfeller ser vi at våre brukere ønsker å bruke denne komponenten som en navigasjonsrekke med lenker. Disse to bruksområdene har forskjellige hensyn når det kommer til semantikk og tilgjengelighet, og komponenten kommer derfor med to forskjellige interaksjonsmønstre.

Dersom du ønsker å bruke den som en inline navigasjon av innhold på siden, så vil fanene oppføre seg slik som WAI-ARIA-kravene sier de skal, og ellers vil de bare være som en rekke med lenker.

Avhengigheter

Ved bruk av tag eller ikon i fanene:

  • pkt-tag
  • pkt-icon

Bruk uten Vue eller React

Dersom denne komponenten skal oppfylle krav for universell utforming må den utvides med noe JavaScript for å kontrollere tastaturnavigasjonen. Dette kommer bakt inn i Vue- og Reactkomnponentene, men må legges til spesielt ellers.

Vi har laget en klasse som kan brukes “ut av boksen” dersom dere ikke ønsker å skrive denne funksjonaliteten selv. Den kan dere finne på vår CDN eller i pakken punkt-css under /dist/scripts/pkt-tags.js.

Eksempel på bruk:

import PktTabs from "@oslokommune/punkt-css/dist/scripts/pkt-tabs.js";
const tabList1 = new PktTabs(
  document.getElementById("MineTabs"),
  document.getElementById("MineTabsPaneler"),
);
document.querySelectorAll("#MineTabs [role=tab]").forEach((tab, index) => {
  tab.addEventListener("click", (event) => {
    event.preventDefault();
    tabList1.setActiveByIndex(index);
  });
});

Varianter

For å endre innhold på siden

One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin.
He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections.
The bedding was hardly able to cover it and seemed ready to slide off any moment.
His many legs, pitifully thin compared with the size of the rest of him, waved about helplessly as he looked.
"What‘s happened to me?" he thought. It wasn‘t a dream.
<div class="pkt-tabs" id="PktTabs1">
  <div class="pkt-tabs__list" role="tablist">
    <button
      id="tab-1"
      type="button"
      class="pkt-tabs__button pkt-link-button active"
      aria-selected="true"
      aria-controls="panel-1"
      role="tab"
    >
      Tab 1<span class="pkt-tag pkt-tag--yellow pkt-tag--small">Tag</span>
    </button>
    <button
      id="tab-2"
      type="button"
      class="pkt-tabs__button pkt-link-button"
      role="tab"
      aria-controls="panel-2"
      aria-selected="false"
    >
      Tab 2
    </button>

    ...

    <button
      id="tab-5"
      type="button"
      class="pkt-tabs__button pkt-link-button"
      aria-selected="false"
      role="tab"
      aria-controls="panel-5"
    >
      <span class="pkt-icon pkt-icon--small">
        <svg viewBox="0 0 32 32">
          <use href="#user"></use>
        </svg>
      </span>
      Tab 5
    </button>

  </div>
</div><div class="pkt-tabpanels" id="PktTabs1Panels" aria-live="polite">
  <div
    id="panel-1"
    class="p-size-20"
    role="tabpanel"
    aria-labelledby="tab-1"
  >
    One morning, when Gregor Samsa woke from troubled dreams, he found
    himself transformed in his bed into a horrible vermin.
  </div>
  <div
    id="panel-2"
    class="p-size-20 pkt-hide"
    role="tabpanel"
    aria-labelledby="tab-2"
  >
    He lay on his armour-like back, and if he lifted his head a little he
    could see his brown belly, slightly domed and divided by arches into
    stiff sections.
  </div>
  
  ...

  <div
    id="panel-5"
    class="p-size-20 pkt-hide"
    role="tabpanel"
    aria-labelledby="tab-5"
  >
    "What‘s happened to me?" he thought. It wasn‘t a dream.
  </div>
</div>
<script>
  import PktTabs from "@oslokommune/punkt-css/dist/scripts/pkt-tabs.js";
  const tabList1 = new PktTabs(
    document.getElementById("PktTabs1"),
    document.getElementById("PktTabs1Panels")
  )
  document.querySelectorAll("#PktTabs1 [role=tab]").forEach((tab, index) => {
    tab.addEventListener("click", (event) => {
      event.preventDefault()
      tabList1.setActiveByIndex(index)
    })
  })
</script>
<template>
  <PktTabs :tabs="tabs" @onTabSelected="changeContent" />
  <div :id="`tabpanel-${visibleContent}`" role="tabpanel" aria-live="polite">
    {{ content[visibleContent] }}
  </div>
</template>

<script setup>
  const visibleContent = ref(0);
  const changeContent = (index) => {
    visibleContent = index;
  };
  const tabs = [
    {
      text: "Tab 1",
      tag: {
        text: "Tag",
      },
      active: i === visibleContent,
    },
    {
      text: "Tab 2",
      active: i === visibleContent,
    },
    {
      text: "Tab 3",
      active: i === visibleContent,
    },
    {
      text: "Tab 4",
      active: i === visibleContent,
    },
    {
      text: "Tab 5",
      icon: "user",
      active: i === visibleContent,
    },
  ];
  const content = [
    "One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin.",
    "He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections.",
    "The bedding was hardly able to cover it and seemed ready to slide off any moment.",
    "His many legs, pitifully thin compared with the size of the rest of him, waved about helplessly as he looked.",
    '"What‘s happened to me?" he thought. It wasn‘t a dream.',
    "His room, a proper human room although a little too small, lay peacefully between its four familiar walls.",
    "A collection of textile samples lay spread out on the table - Samsa was a travelling salesman - and above it there hung a picture that he had recently cut out of an illustrated magazine,",
  ];
</script>
const [visibleContent, setVisibleContent] = useState(0)
const [tabs, setTabs] = useState([
  {
    text: 'Tab 1',
    tag: {
      text: 'Tag',
    },
    active: i === visibleContent,
  },
  {
    text: 'Tab 2',
    active: i === visibleContent,
  },
  {
    text: 'Tab 3',
    active: i === visibleContent,
  },
  {
    text: 'Tab 4',
    active: i === visibleContent,
  },
  {
    text: 'Tab 5',
    icon: 'user',
    active: i === visibleContent,
  },
])
const content = [
  'One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin.',
  'He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections.',
  'The bedding was hardly able to cover it and seemed ready to slide off any moment.',
  'His many legs, pitifully thin compared with the size of the rest of him, waved about helplessly as he looked.',
  '"What‘s happened to me?" he thought. It wasn‘t a dream.',
  'His room, a proper human room although a little too small, lay peacefully between its four familiar walls.',
  'A collection of textile samples lay spread out on the table - Samsa was a travelling salesman - and above it there hung a picture that he had recently cut out of an illustrated magazine,',
]
const changeContent = (id) => {
  setTabs(tabs.map((tab, i) => ({...tab, active: i === visibleContent})))
}

return (

{" "}
<PktTabs tabs={tabs} onTabSelected={changeContent} />

  <div
    id={`tabpanel-${visibleContent}`}
    role="tabpanel"
    aria-live="polite"

>

    {content[visibleContent]}

  </div>
)

For å navigere til en annen side (navigasjon)

<div class="pkt-tabs">
  <div class="pkt-tabs__list" role="navigation">
    <a class="pkt-tabs__link active" href="#">Tab 1</a>
    <a class="pkt-tabs__link" href="#">Tab 2</a>
    <a class="pkt-tabs__link" href="#">Tab 3</a>
    <a class="pkt-tabs__link" href="#">Tab 4</a>
    <a class="pkt-tabs__link" href="#">Tab 5</a>
    <a class="pkt-tabs__link" href="#">Tab 6</a>
    <a class="pkt-tabs__link" href="#">Tab 7</a>
    <a class="pkt-tabs__link" href="#">Tab 8</a>
    <a class="pkt-tabs__link" href="#">Tab 9</a>
    <a class="pkt-tabs__link" href="#">Tab 10</a>
    <a class="pkt-tabs__link" href="#">Tab 11</a>
    <a class="pkt-tabs__link" href="#">Tab 12</a>
    <a class="pkt-tabs__link" href="#">Tab 13</a>
    <a class="pkt-tabs__link" href="#">Tab 14</a>
    <a class="pkt-tabs__link" href="#">Tab 15</a>
  </div>
</div>
<template>
  <PktTabs :tabs="tabs" , :arrowNav="false" />
</template>

<script setup>
  const tabs = [
    {
      text: 'Tab 1',
      href: '#',
      active: true,
    },
    {
      text: 'Tab 2',
      href: '#',
    },
    {
      text: 'Tab 3',
      href: '#',
    },
    ...
  ]
</script>
const tabs = [
  {
    text: 'Tab 1',
    href: '#',
    active: true,
  },
  {
    text: 'Tab 2',
    href: '#',
  },
  {
    text: 'Tab 3',
    href: '#',
  },
  ...
]

return (

  <PktTabs tabs={tabs} arrowNav={false} />
)

CSS-klasser

Block:

  • .pkt-tabs

Elements:

  • .pkt-tabs__list
  • .pkt-tabs__link
  • .pkt-tabs__button
  • .pkt-link-button
  • .pkt-tag
  • .pkt-icon

Modifiers:

  • .pkt-icon--small
  • .pkt-tag--small

Props og events

PropsTypeValidationDefaultBeskrivelse
tabsarrayRequired-Liste av objekter som utgjør fanene – Se neste tabell
arrowNavboolean-trueSettes denne til false vil fanerekken være navigasjon med lenker istedenfor tablist
onTabSelected (React)function--Callback-funksjon som kalles med index av valgt fane

tab-objektet i tabs

KeyTypeValidationDefaultBeskrivelse
textstringRequired-Tekst som vises i fanen
hrefstring--Valgfri lenke-URL til bruk dersom dette er navigasjon, eller for fallback
actionfunction--Valgfri funksjon som skal kalles ved klikk på denne fanen
iconstring--Ikon fra vårt ikonbibliotek som skal vises i fanen
controlsstring--ID til innholdspanelen som denne fanen styrer (aria-controls-attributt)
tagobjectSom PktTag-Tar text- og skin-verdier som matcher det som kan sendes til PktTag
activeboolean--Er denne fanen aktiv? true/false

Events

EventsTypeReturnsBeskrivelse
onTabSelectedVueintegerReturnerer index på valgt fane

Les mer