{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "skip-link",
  "type": "registry:ui",
  "title": "Skip Link",
  "description": "The \"jump to main content\" link that satisfies WCAG 2.4.1 (Bypass Blocks): an `sr-only` anchor that pops into the top-left corner the moment it takes focus, letting a keyboard user step past the header and nav in one Tab.",
  "author": "ofri-peretz <https://github.com/ofri-peretz>",
  "categories": [
    "a11y",
    "primitive"
  ],
  "dependencies": [],
  "registryDependencies": [
    "https://ds.interlace.tools/r/theme.json",
    "https://ds.interlace.tools/r/cn.json"
  ],
  "files": [
    {
      "path": "registry/interlace-ui/skip-link.tsx",
      "target": "components/ui/skip-link.tsx",
      "type": "registry:ui",
      "content": "import * as React from 'react';\n\n// @interlace/skip-link v1.1.0 — Interlace design system.\n// Docs, props and live preview: https://ds.interlace.tools/c/skip-link\n// What changed since: https://ds.interlace.tools/c/skip-link#history\n// Generated banner — keep it, the upgrade diff reads this version.\n\n/**\n * @interlace/ui — SkipLink\n *\n * The \"jump to main content\" link that satisfies WCAG 2.4.1 (Bypass Blocks):\n * an `sr-only` anchor that pops into the top-left corner the moment it takes\n * focus, letting a keyboard user step past the header and nav in one Tab.\n *\n * It only earns that if it is the first focusable element in the document.\n * A mouse user never sees it.\n *\n * Pair this with a `<main id=\"main\">` (or whichever target you point at).\n * The target MUST be focusable (set `tabIndex={-1}` on `<main>` so the skip\n * action moves focus into it, not just the scroll position).\n *\n * The visible state is painted entirely by `focus-visible:` utilities — the\n * link is `sr-only` until then, so a browser that resolves focus-visible\n * differently changes when it appears, not whether it works.\n *\n * ## Anatomy\n *\n *   SkipLink                          (anchor — data-min-viewport=320)\n *     └─ children                     (default: \"Skip to main content\")\n *\n * ## MIN_VIEWPORT — 320\n *\n * The first interactive element a keyboard user encounters on the page.\n * Must work on every device that ships a physical keyboard or assistive-tech\n * tab-stop emulator — i.e. all of them.\n *\n * | Rule | Concept                          | Where in this file                                          |\n * | ---- | -------------------------------- | ----------------------------------------------------------- |\n * | R4   | Extends native el                | `React.ComponentProps<'a'> & SkipLinkProps`                 |\n * | R6   | data-slot on root                | `data-slot=\"skip-link\"`                                     |\n * | R7   | className merged + ...rest       | `cn(BASE, className)` + `{...props}`                        |\n * | R8   | No isXxx                         | n/a — no boolean variants                                   |\n * | R14  | Declares min viewport            | `data-min-viewport={String(MIN_VIEWPORT)}` + exported const |\n * | R18  | Tailwind only                    | Zero inline `style`; utility classes only                   |\n * | R19  | Tokens only                      | bg-background / text-foreground / focus-visible:ring-ring   |\n * | R20  | AA contrast                      | Visible state uses semantic tokens that clear AA / AAA      |\n * | R25  | Server component                 | No hooks → no `'use client'`                                |\n * | R26  | A11y from native el              | `<a href>` is the native element; focus + activation inherit |\n */\n\nimport { cn } from '@/lib/utils';\n\nexport const MIN_VIEWPORT = 320 as const;\n\ntype SkipLinkProps = React.ComponentProps<'a'> & {\n  /**\n   * Hash target for the skip action. Defaults to `#main` — pair with a\n   * `<main id=\"main\" tabIndex={-1}>` so focus moves into the content\n   * region, not just the scroll position.\n   */\n  href?: string;\n};\n\nexport const SkipLink = React.forwardRef<HTMLAnchorElement, SkipLinkProps>(\n  ({ className, href = '#main', children, ...props }, ref) => (\n    <a\n      ref={ref}\n      href={href}\n      data-slot=\"skip-link\"\n      data-min-viewport={String(MIN_VIEWPORT)}\n      className={cn(\n        // Visually hidden by default — same technique as VisuallyHidden but\n        // explicitly inline so this primitive carries no implicit dep.\n        'sr-only',\n        // Pop into view when focus-visible. Top-left corner, above sticky\n        // headers (`z-50`), with the DS focus ring contract.\n        'focus-visible:not-sr-only focus-visible:fixed focus-visible:left-4 focus-visible:top-4 focus-visible:z-50',\n        'focus-visible:rounded-md focus-visible:border focus-visible:border-border',\n        'focus-visible:bg-background focus-visible:px-4 focus-visible:py-2',\n        'focus-visible:text-sm focus-visible:font-medium focus-visible:text-foreground',\n        'focus-visible:shadow-lg',\n        'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n        className,\n      )}\n      {...props}\n    >\n      {children ?? 'Skip to main content'}\n    </a>\n  ),\n);\nSkipLink.displayName = 'SkipLink';\n"
    }
  ],
  "meta": {
    "tier": "primitive",
    "client": false,
    "minViewport": 320,
    "loading": false,
    "version": "1.1.0",
    "since": "1.0.0"
  },
  "docs": "## @interlace/skip-link\n\nInstalled to `components/ui/skip-link.tsx`.\n\n```tsx\nimport { /* … */ } from '@/components/ui/skip-link';\n```\n\nProps, a11y contract, live preview and source: https://ds.interlace.tools/c/skip-link\n\nRequires the `@interlace/theme` CSS baseline (installed automatically as a registry dependency)."
}
