Käyttötarkoitus
Komponenttia käytetään sivupalkissa sijaitsevan navigaation toteuttamiseen silloin, kun käytetään sivupohjaa, jossa päänavigaationa on Sidebar.
Komponentti muuntuu myös mobiilinavigaatioksi.
Komponentti toimii kehyksenä navigaatiolle. Varsinainen navigaatiorakenne toteutetaan valikon sisään sijoitettavalla Nav-komponentilla.
Komponenttia ei kannata käyttää erillisen mobiilinavigaation toteuttamiseen muissa sivupohjissa. OverlayNav-komponentti soveltuu tähän paremmin.
Saavutettavuus
Jos sivulla on useita navigaatioelementtejä (HTML:n nav-elementti), navigaatio on hyvä erottaa muista navigaatioelementeistä aria-label-attribuutilla.
Sidebar-komponentin sisään lisättäviä linkki- ja painikelistoja voi tarvittaessa erottaa visuaalisesti lisäämällä listojen väliin hr-tagin (ks. esimerkki alla). Mikäli ruudunlukijan ei haluta lukevan erotinviivaa tulee siihen lisätä aria-hidden-attribuutti.
Sidebar lukitsee kohdistuksen ja ruudunlukijan virtuaalikursorin valikon elementteihin sen ollessa auki ja isOverlay-tilassa.
Kohdistus palautetaan sivupalkin avanneeseen elementtiin, sivupalkin sulkeutuessa.
Esimerkit
Alla olevat esimerkit on muokattu koodieditoria varten, joten ne eivät täysin vastaa todellista käyttöä. Oikea esimerkki löytyy Sivupohja Sidebar-navigaatiolla.
Sivupalkin toteutus
Navigaatio toteutetaan Sidebar-komponentin sisään Nav-komponentilla.
<div className="kds-overflow-hidden kds-h-screen kds-bg-background">
<Sidebar
aria-label="Päänavigaatio"
className="kds-relative kds-h-full"
closeLabel="Sulje navigaatiovalikko"
description="Sivun tai palvelun lyhyt kuvausteksti"
isOpen={true}
isOverlay={false}
logo={
<a href="#" aria-label="Etusivulle" className="kds-inline-block">
<LogoKela height="48" width="83" />
</a>
}
title="Sivun tai palvelun otsikko"
>
<Nav>
<NavHeading>Painikkeet</NavHeading>
<NavLink as="button" linkColor iconBefore={<IconUiCaretLeft />}>
Takaisin
</NavLink>
<NavList>
<NavListItem>
<NavLink as="button">Painike</NavLink>
</NavListItem>
<NavListItem>
<NavLink as="button" active>
Painike - aktiivinen sivu
</NavLink>
</NavListItem>
<NavListItem>
<NavLink as="button" iconAfter={<IconUiCaretRight />}>
Painike kuvakkeella
</NavLink>
</NavListItem>
<NavListItem>
<NavLink as="button" disabled>
Painike, estetty
</NavLink>
</NavListItem>
<NavListItem>
<NavLink as="button" active disabled>
Painike, aktiivinen ja estetty
</NavLink>
</NavListItem>
</NavList>
<hr />
<NavHeading>Linkit</NavHeading>
<NavList>
<NavListItem>
<NavLink href="#">Linkki</NavLink>
</NavListItem>
<NavListItem>
<NavLink href="#" active>
Linkki, aktiivinen
</NavLink>
</NavListItem>
<NavListItem>
<NavLink href="#" iconAfter={<IconUiCaretRight />}>
Linkki kuvakkeella
</NavLink>
</NavListItem>
<NavListItem>
<NavLink disabled>Linkki, estetty</NavLink>
</NavListItem>
<NavListItem>
<NavLink active disabled>
Linkki, aktiivinen ja estetty
</NavLink>
</NavListItem>
</NavList>
<hr />
<NavHeading className="kds-mt-8">Oikopolut</NavHeading>
<NavList>
<NavListItem>
<NavLink href="#" iconBefore={<IconDecoPersonsCircle className="kds-text-primary" size="m" />}>
Asiakaspalvelu
</NavLink>
</NavListItem>
<NavListItem>
<NavLink href="#" iconBefore={<IconDecoInfoCircle className="kds-text-primary" size="m" />}>
Hakemuksesta päätökseen
</NavLink>
</NavListItem>
<NavListItem>
<NavLink href="#" iconBefore={<IconDecoMathCircle className="kds-text-primary" size="m" />}>
Laskurit
</NavLink>
</NavListItem>
</NavList>
</Nav>
</Sidebar>
</div>
Sivupalkin tilat
Overlay-tilassa valikko kelluu sisällön päällä ja kohdistus lukitaan valikon sisään.
Overlay-tilan asettamiseen tietyssä ruudunkoossa voi käyttää useMediaQuery-hookia.
function ExampleSidebar() {
const triggerRef = useRef(null);
const [isOpen, setIsOpen] = useState(true);
const [isToggleOpen, setIsToggleOpen] = useState(false);
const [isOverlay, setIsOverlay] = useState(false);
const handleNavClick = (e) => {
e.preventDefault();
if (isOverlay) {
setIsOpen(false);
}
};
return (
<>
<Button
appearance="outline"
className="kds-mb-6 kds-mr-4"
onClick={(e) => {
e.stopPropagation();
setIsOpen(!isOpen);
}}
ref={triggerRef}
>
{isOpen ? "Piilota valikko" : "Näytä valikko"}
</Button>
<Button
appearance="outline"
onClick={(e) => {
e.stopPropagation();
setIsOverlay(!isOverlay);
}}
className="kds-mb-6"
>
Overlay-tila: {isOverlay ? "päällä" : "pois päältä"}
</Button>
<div className="kds-overflow-hidden kds-h-screen kds-bg-background">
<Sidebar
aria-label="Päänavigaatio"
className="kds-relative kds-h-full" // Vain KDS-dokumentaation esimerkille
isOpen={isOpen}
isOverlay={isOverlay}
logo={
<a href="#" aria-label="Etusivulle" className="kds-inline-block" onClick={handleNavClick}>
<LogoKela height="48" width="83" />
</a>
}
onClose={() => setIsOpen(!isOpen)}
triggerRef={triggerRef}
>
<Nav>
<NavLink as="button" linkColor iconBefore={<IconUiCaretLeft />}>
Takaisin
</NavLink>
<NavHeading className="kds-mt-2">
<NavLink href="#" active onClick={handleNavClick}>
Asumisen tuet
</NavLink>
</NavHeading>
<NavList>
<NavListItem>
<NavLink
href="#"
onClick={handleNavClick}
toggle={
<NavLinkToggle
aria-controls="yleinen-asumistuki-sub-pages"
aria-expanded={isToggleOpen ? "true" : "false"}
aria-label={isToggleOpen ? "Sulje valikko" : "Avaa valikko"}
isOpen={isToggleOpen}
onClick={() => setIsToggleOpen(!isToggleOpen)}
/>
}
>
Yleinen asumistuki
</NavLink>
{isToggleOpen && (
<NavList id="yleinen-asumistuki-sub-pages">
<NavListItem>
<NavLink href="#" onClick={handleNavClick}>
Kuka voi saada
</NavLink>
</NavListItem>
<NavListItem>
<NavLink href="#" onClick={handleNavClick}>
Määrä ja maksaminen
</NavLink>
</NavListItem>
</NavList>
)}
</NavListItem>
<NavListItem>
<NavLink href="#" onClick={handleNavClick}>
Mihin menoihin tukea voi saada?
</NavLink>
</NavListItem>
<NavListItem>
<NavLink href="#" onClick={handleNavClick}>
Miten tulot vaikuttavat
</NavLink>
</NavListItem>
<NavListItem>
<NavLink href="#" onClick={handleNavClick}>
Milloin asumistuki täytyy tarkistaa?
</NavLink>
</NavListItem>
<NavListItem>
<NavLink href="#" onClick={handleNavClick}>
Muut asumisen tuet
</NavLink>
</NavListItem>
</NavList>
<hr />
<NavHeading className="kds-mt-8">
<NavLink>Oikopolut</NavLink>
</NavHeading>
<NavList>
<NavListItem>
<NavLink
href="#"
iconBefore={<IconDecoPersonsCircle className="kds-text-primary" size="m" />}
onClick={handleNavClick}
>
Asiakaspalvelu
</NavLink>
</NavListItem>
<NavListItem>
<NavLink
href="#"
iconBefore={<IconDecoInfoCircle className="kds-text-primary" size="m" />}
onClick={handleNavClick}
>
Hakemuksesta päätökseen
</NavLink>
</NavListItem>
<NavListItem>
<NavLink
href="#"
iconBefore={<IconDecoMathCircle className="kds-text-primary" size="m" />}
onClick={handleNavClick}
>
Laskurit
</NavLink>
</NavListItem>
</NavList>
</Nav>
</Sidebar>
</div>
</>
);
}
Sivupalkin sulkeminen ja kohdistuksen palautus
Overlay-tilassa kohdistus palautuu sivupalkin sulkeutuessa siihen elementtiin, joka avasi sivupalkin (triggerRef tai document.activeElement).
Kohdistus on mahdollista siirtää johonkin toiseen elementtiin, asettamalla returnFocus={false} ja toteuttamalla kohdistuksen siirron sovelluksessa.
function ExampleSidebar() {
const triggerRef = useRef(null);
const [isOpen, setIsOpen] = useState(true);
const [isOverlay, setIsOverlay] = useState(false);
const [isToggleOpen, setIsToggleOpen] = useState(false);
const handleNavClick = (e) => {
e.preventDefault();
if (isOverlay) {
setIsOpen(false);
setTimeout(() => {
triggerRef.current?.focus();
});
}
};
const handleOnClose = (_e, { reason }) => {
setIsOpen(false);
if (["escape", "outside", "close"].includes(reason)) {
setTimeout(() => {
triggerRef.current?.focus();
});
}
};
return (
<>
<Button
appearance="outline"
className="kds-mb-6 kds-mr-4"
onClick={(e) => {
e.stopPropagation();
setIsOpen(!isOpen);
}}
ref={triggerRef}
>
{isOpen ? "Piilota valikko" : "Näytä valikko"}
</Button>
<Button
appearance="outline"
onClick={(e) => {
e.stopPropagation();
setIsOverlay(!isOverlay);
}}
className="kds-mb-6"
>
Overlay-tila: {isOverlay ? "päällä" : "pois päältä"}
</Button>
<div className="kds-overflow-hidden kds-h-screen kds-bg-background">
<Sidebar
aria-label="Päänavigaatio"
className="kds-relative kds-h-full" // Vain KDS-dokumentaation esimerkille
isOpen={isOpen}
isOverlay={isOverlay}
logo={
<a href="#" aria-label="Etusivulle" className="kds-inline-block" onClick={handleNavClick}>
<LogoKela height="48" width="83" />
</a>
}
onClose={handleOnClose}
returnFocus={false}
>
<Nav>
<NavLink as="button" linkColor iconBefore={<IconUiCaretLeft />}>
Takaisin
</NavLink>
<NavHeading className="kds-mt-2">
<NavLink href="#" active onClick={handleNavClick}>
Asumisen tuet
</NavLink>
</NavHeading>
<NavList>
<NavListItem>
<NavLink
href="#"
onClick={handleNavClick}
toggle={
<NavLinkToggle
aria-controls="yleinen-asumistuki-2-sub-pages"
aria-expanded={isToggleOpen ? "true" : "false"}
aria-label={isToggleOpen ? "Sulje valikko" : "Avaa valikko"}
isOpen={isToggleOpen}
onClick={() => setIsToggleOpen(!isToggleOpen)}
/>
}
>
Yleinen asumistuki
</NavLink>
{isToggleOpen && (
<NavList id="yleinen-asumistuki-2-sub-pages">
<NavListItem>
<NavLink href="#" onClick={handleNavClick}>
Kuka voi saada
</NavLink>
</NavListItem>
<NavListItem>
<NavLink href="#" onClick={handleNavClick}>
Määrä ja maksaminen
</NavLink>
</NavListItem>
</NavList>
)}
</NavListItem>
<NavListItem>
<NavLink href="#" onClick={handleNavClick}>
Mihin menoihin tukea voi saada?
</NavLink>
</NavListItem>
<NavListItem>
<NavLink href="#" onClick={handleNavClick}>
Miten tulot vaikuttavat
</NavLink>
</NavListItem>
<NavListItem>
<NavLink href="#" onClick={handleNavClick}>
Milloin asumistuki täytyy tarkistaa?
</NavLink>
</NavListItem>
<NavListItem>
<NavLink href="#" onClick={handleNavClick}>
Muut asumisen tuet
</NavLink>
</NavListItem>
</NavList>
<hr />
<NavHeading className="kds-mt-8">
<NavLink>Oikopolut</NavLink>
</NavHeading>
<NavList>
<NavListItem>
<NavLink
href="#"
iconBefore={<IconDecoPersonsCircle className="kds-text-primary" size="m" />}
onClick={handleNavClick}
>
Asiakaspalvelu
</NavLink>
</NavListItem>
<NavListItem>
<NavLink
href="#"
iconBefore={<IconDecoInfoCircle className="kds-text-primary" size="m" />}
onClick={handleNavClick}
>
Hakemuksesta päätökseen
</NavLink>
</NavListItem>
<NavListItem>
<NavLink
href="#"
iconBefore={<IconDecoMathCircle className="kds-text-primary" size="m" />}
onClick={handleNavClick}
>
Laskurit
</NavLink>
</NavListItem>
</NavList>
</Nav>
</Sidebar>
</div>
</>
);
}
Tunnetut ongelmat
Kohdistuksen palautus
Safari ei aseta document.activeElement-elementtiä, kun painiketta klikataan hiirellä tai painetaan kosketusnäytöllä. Välitä komponentille triggerRef-propin kautta elementti, johon kohdistus palautetaan.