# Skip Link

> A link that skips past the menu to the main content. A CSS component with one class and no JavaScript.

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

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:

**Plain HTML**

```html
<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 -->
```

```html
<a class="lt-skip-link" href="#main-content">Skip to main content</a>
```

**TypeScript**

```ts
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:

```tsx
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:

```ts
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:

```html
<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

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

| 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](/customising.md) for how the variables and the layer work.

## 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.
