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