Skip link
StableA “Skip to content” link that stays hidden until the first Tab, then jumps past the header to #main.
The first thing keyboard and switch users reach on a page. It is visually hidden until it has focus, then appears as a small inverted label in the top-left corner. Enter jumps to the element with id="main".
Updated View source
Reveal it with Tab
import { useRef } from 'react'import { Logo } from '@rchursin/brand/Logo'import { SkipLink } from '@rchursin/home/Chrome'import { Button } from '@rchursin/product/ui'import { Link } from '@rchursin/product/lib/router'
/** * The top of a page, with the skip link first. It is hidden until it has focus: press Tab from * the Copy button above, or use the button below. Enter jumps to #main, which on this site is * the start of this page's content. */export default function SkipLinkFocus() { const page = useRef<HTMLDivElement>(null) const show = () => page.current?.querySelector<HTMLAnchorElement>('a[href="#main"]')?.focus()
return ( <div className="flex w-full max-w-lg flex-col items-center gap-5"> <div ref={page} className="relative w-full overflow-hidden rounded-xl bg-surface ring-1 ring-line"> <SkipLink /> <div className="flex h-14 items-center gap-6 border-b border-line px-4">Usage
import { SkipLink } from '@rchursin/home/Chrome'<SkipLink /><SiteHeader /><main id="main" tabIndex={-1}>…</main>Accessibility
Keyboard
| Key | What it does |
|---|---|
| Tab | From the top of the page, the first Tab focuses the link and shows it. |
| Enter | Jumps to #main and moves focus there. |
- Meets WCAG 2.4.1 Bypass Blocks: one key press skips the header and its links.
- It is sr-only while it doesn’t have focus (not-focus:sr-only), so screen readers always find it; on focus it shows as a padded label, absolutely positioned 12 pixels from the top-left of the nearest positioned ancestor.
- The target is fixed: give <main> id="main". Add tabIndex={-1} to <main> so every browser moves focus there, not just the scroll position.
- White on ink (ink on white in dark mode) gives the label 19.8:1 contrast.
Guidelines
Do
- Make it the first focusable element on the page, before the header.
- Keep the words plain: “Skip to content”.
Don’t
- Don’t hide it with display: none; it must be focusable.
- Don’t point it at an id that doesn’t exist.
In use
Related
- Site headerThe home pages’ sticky header in three styles: a full bar, a floating glass pill and a minimal mono row.
- FocusA 2px ring in the text colour, outside or inside the edge, plus the lit-metal buttons’ own ring. Keyboard only.
- Link & routerA small router with no dependencies: Link changes page without a reload, useRouter says where you are, in history or hash mode.
Source
The component’s own files, exactly as they run on this site.
/** * Site header and footer shared by the home pages, in three header styles: * - bar Tailwind Plus header: logo left, links, actions right * - floating Aceternity floating pill over the page * - minimal logo + a few mono text links, for the developer-first page * * Details: the header is clear at the top of the page and frosts (glass + hairline) once you * scroll; the logo's underscore blinks like a cursor on hover; links draw their underline in; * the mobile menu eases down from the bar. */import { useId, useRef, useState, type ReactNode } from "react"import { Logo } from "../brand/Logo"import { cx } from "../components/cx"import { MenuIcon } from "../components/icons"import { useScrolled } from "../components/motion"import { useCurrentYear } from "../product/lib/hydration"import { nav } from "./content"import { ButtonLink, Container } from "./ui"
export function SkipLink() {