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
<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
Props | Type | Validation | Default | Beskrivelse |
---|---|---|---|---|
tabs | array | Required | - | Liste av objekter som utgjør fanene – Se neste tabell |
arrowNav | boolean | - | true | Settes 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
Key | Type | Validation | Default | Beskrivelse |
---|---|---|---|---|
text | string | Required | - | Tekst som vises i fanen |
href | string | - | - | Valgfri lenke-URL til bruk dersom dette er navigasjon, eller for fallback |
action | function | - | - | Valgfri funksjon som skal kalles ved klikk på denne fanen |
icon | string | - | - | Ikon fra vårt ikonbibliotek som skal vises i fanen |
controls | string | - | - | ID til innholdspanelen som denne fanen styrer (aria-controls-attributt) |
tag | object | Som PktTag | - | Tar text - og skin -verdier som matcher det som kan sendes til PktTag |
active | boolean | - | - | Er denne fanen aktiv? true /false |
Events
Events | Type | Returns | Beskrivelse |
---|---|---|---|
onTabSelected | Vue | integer | Returnerer index på valgt fane |
Les mer