Skip Link
Otherwise someone navigating by keyboard has to go through the whole menu on every single page. The link sits off screen until it gets focus, and is usually the first element in <body>.
How to use it
Section titled “How to use it”The link sits off screen until it gets focus. The preview below forces it into view, so you can see how it looks when it is visible. The markup is the same as in a real page:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/tokens/tokens.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/skip-link/skip-link.css"><!-- Or everything in one file: https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/dist/lotek.css --><a class="lt-skip-link" href="#main-content">Skip to main content</a>import "@lo-tek/interfaces/tokens.css"import "@lo-tek/interfaces/skip-link.css"lt is used in two ways, and which one depends on whether you create the element or find it.
If you create the markup, spread the attributes in. That is the way in React, Astro and anything else that renders:
import { lt } from "@lo-tek/interfaces/react"
<a {...lt.skipLink()} href="#main-content">Skip to main content</a>The import is from /react here, since the block is JSX. From there the keys are className and htmlFor. In Astro and anything else without React, import @lo-tek/interfaces and you get class and for.
If you have the element in a variable, set them on it with setAttributes. That is the way without JSX, whether you just created the element or found it in a page the server sent:
import { lt } from "@lo-tek/interfaces"
const link = document.createElement("a")link.href = "#main-content"link.textContent = "Skip to main content"
lt.setAttributes(link, lt.skipLink())document.body.prepend(link)The placement is the only thing that comes in addition. The link should be the first thing in <body>, and the target has to be able to receive focus:
<body> <a class="lt-skip-link" href="#main-content">Skip to main content</a>
<header>…</header>
<main id="main-content" tabindex="-1">…</main></body>tabindex="-1" on the target is necessary. Without it the browser moves the view there, but not focus: document.activeElement becomes <body>, and the screen reader is not told that the user has reached the content. With the attribute <main> gets focus, and the assistive technology reads out where the user is. The keyboard order is not the problem, since the browser continues from the target after the jump anyway. It is the focus and the announcement that are missing without the attribute.
Why it cannot be hidden
Section titled “Why it cannot be hidden”The link is moved off screen with transform, not with display: none or visibility: hidden. The last two take the element out of the keyboard order, and the link then does not exist for the person who needs it.
It appears on :focus, not :focus-visible. Focus set from code after a mouse click does not count as visible focus, and the link would then stay hidden for someone who jumps there from a script, for example from a button. After a keystroke, and right after the page has loaded, it counts as visible, but it is the mouse click that decides the choice.
Classes you can style
Section titled “Classes you can style”| Class | What it is |
|---|---|
.lt-skip-link | The link |
| Variable | Default |
|---|---|
--lt-skip-link-padding | var(--lt-spacing-2) var(--lt-spacing-4) |
--lt-skip-link-radius | var(--lt-spacing-1) |
See Customising for how the variables and the layer work.
Accessibility
Section titled “Accessibility”- The link should be the first element on the page to get focus. If it comes after the menu, it helps nobody.
- The text should say where you end up. “Skip to main content”, not “Skip”.
- If the page has both a menu and a search at the top, one more link can be justified, for example to the search. More than two become a menu in themselves.
- Test it with Tab as the first keystroke after the page has loaded. That is the only way to see that it works.