{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "link",
  "type": "registry:ui",
  "title": "Link",
  "description": "A native <a href> with shadcn styling — default (underlined), muted, and hover-underline variants, plus an external treatment that opens a new tab, sets rel=\"noopener noreferrer\", and announces \"(opens in new tab)\".",
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ui/link.tsx",
      "type": "registry:ui",
      "target": "components/ui/link.tsx",
      "content": "/** @jsxImportSource hono/jsx */\nimport type { PropsWithChildren } from \"hono/jsx\"\nimport { cn, type ClassValue } from \"@/registry/lib/cn\"\n\n// Link — shadcn-htmx, htmx v4 + Tailwind v4.\n//\n// shadcn/ui has no standalone \"link\" primitive — it styles links through the\n// Button `link` variant and the `typography` docs. We ship a dedicated,\n// text-first anchor instead. Anatomy/intent cross-checked against the Button\n// `link` variant: repos/shadcn-ui/apps/v4/registry/new-york-v4/ui/button.tsx.\n//\n// Accessibility contract — WAI-ARIA APG Link pattern:\n//   repos/aria-practices/content/patterns/link/link-pattern.html\n// The APG itself says: \"Authors are strongly encouraged to use a native host\n// language link element, such as an HTML <a> element with an href attribute.\"\n// So we render a real <a href>. That gives us, for free and without any JS:\n//   - the implicit `link` role (MDN: <a> has role=link when href is present —\n//     repos/mdn/files/en-us/web/html/reference/elements/a/index.md \"Implicit\n//     ARIA role\"),\n//   - Enter activates + moves focus to the target (the APG keyboard contract —\n//     link-pattern.html \"Keyboard Interaction\": Enter executes the link),\n//   - browser affordances the APG example flags as lost when you fake a link\n//     with role=link on a <span>: open-in-new-tab, copy-link, drag, Shift+F10\n//     context menu.\n// The APG link *examples* (link/examples/link.html) only reach for\n// role=link + tabindex=0 + onkeydown when the markup genuinely cannot be an\n// <a> (a <span> or <img>). We expose that fallback via `as` + `role=\"link\"`,\n// but the default — and the path we document — is the native element.\n//\n// `external` sets target/rel and renders a visible \"opens in new tab\" icon +\n// visually-hidden text, per MDN's \"External links\" guidance\n// (a/index.md \"External links and linking to non-HTML resources\"). Modern\n// browsers treat target=\"_blank\" as rel=\"noopener\" implicitly; we still emit\n// rel=\"noopener noreferrer\" so the protection is explicit and back-compatible.\n\nexport type LinkVariant =\n  | \"default\" // underlined, primary colour — reads as a link in prose\n  | \"muted\" // muted-foreground, underlined — low-emphasis inline link\n  | \"hover\" // no underline at rest, underline on hover/focus — nav/menu link\n\nconst base =\n  \"inline-flex items-center gap-1 rounded-sm font-medium text-primary underline-offset-4 transition-colors outline-none \" +\n  // Native <a> is keyboard-focusable; render the same focus ring as the rest\n  // of the library so the focus state is obvious. ring-ring/50 + a 2px ring.\n  \"focus-visible:ring-[3px] focus-visible:ring-ring/50 \" +\n  // role=link fallback (non-anchor) must look identical and not show a text\n  // cursor; the platform won't give it pointer affordance the way <a> does.\n  \"[&[role=link]]:cursor-pointer \" +\n  // Decorative SVGs inside the link (the external-link glyph) get sized here\n  // so callers don't have to.\n  \"[&>svg]:pointer-events-none [&>svg]:size-3.5 [&>svg]:shrink-0\"\n\nconst variants: Record<LinkVariant, string> = {\n  default: \"underline decoration-primary/40 hover:decoration-primary\",\n  muted:\n    \"text-muted-foreground underline decoration-muted-foreground/40 hover:text-foreground hover:decoration-foreground\",\n  hover: \"no-underline hover:underline\",\n}\n\nexport function linkClasses(opts?: {\n  variant?: LinkVariant\n  class?: ClassValue\n}): string {\n  const variant = opts?.variant ?? \"default\"\n  return cn(base, variants[variant], opts?.class)\n}\n\ntype LinkProps = PropsWithChildren<{\n  variant?: LinkVariant\n  class?: ClassValue\n\n  // The destination. Native <a href>. Omitting href yields a non-link\n  // <a> (generic role) — usually you want href.\n  href?: string\n\n  // Treat the link as external: opens in a new browsing context and appends\n  // the \"opens in new tab\" affordance (icon + SR-only text). See MDN\n  // \"External links\" guidance. Sets target=\"_blank\" rel=\"noopener noreferrer\".\n  external?: boolean\n\n  // Standard <a> attributes (MDN). target/rel are managed by `external` but\n  // can be set explicitly too.\n  target?: \"_self\" | \"_blank\" | \"_parent\" | \"_top\" | (string & {})\n  rel?: string\n  download?: boolean | string\n  hreflang?: string\n  referrerpolicy?: string\n  ping?: string\n  type?: string\n\n  id?: string\n  ariaLabel?: string\n  ariaLabelledby?: string\n  // aria-describedby is a global ARIA attribute valid on the implicit `link`\n  // role (MDN: <a href> exposes role=link). Reference a description distinct\n  // from the link text — e.g. \"PDF, 2MB\" / \"opens in new tab\".\n  ariaDescribedby?: string\n  ariaCurrent?: \"page\" | \"step\" | \"location\" | \"date\" | \"time\" | \"true\" | \"false\"\n\n  // APG fallback only: render a non-anchor element with role=\"link\". The\n  // platform will NOT navigate for you — wire navigation yourself (see docs).\n  // We still add tabindex=0 + role=link so it's reachable and announced.\n  as?: \"a\" | \"span\" | \"button\"\n  role?: \"link\"\n\n  // htmx v4 — e.g. boost a same-origin link into a fetch+swap. See\n  // repos/htmx/www/src/content/reference/.\n  \"hx-get\"?: string\n  \"hx-target\"?: string\n  \"hx-swap\"?: string\n  \"hx-boost\"?: string\n  \"hx-push-url\"?: string\n}>\n\nexport function Link(props: LinkProps) {\n  const {\n    children,\n    variant,\n    class: className,\n    href,\n    external,\n    target,\n    rel,\n    as,\n    role,\n    ariaLabel,\n    ariaLabelledby,\n    ariaDescribedby,\n    ariaCurrent,\n    ...rest\n  } = props\n\n  const Tag: any = as ?? \"a\"\n  const isAnchor = Tag === \"a\"\n\n  // External: open in a new tab and make that explicit. rel=\"noopener\n  // noreferrer\" drops window.opener + the Referer header.\n  const resolvedTarget = external ? (target ?? \"_blank\") : target\n  const resolvedRel = external ? (rel ?? \"noopener noreferrer\") : rel\n\n  // APG fallback: a non-anchor element must be told it's a link (role=link)\n  // and put in the tab order (tabindex=0). A native <a> already has both for\n  // free — never override them. role=\"link\" passed explicitly on an <a> is\n  // ignored (it's already the implicit role).\n  const resolvedRole = isAnchor ? undefined : \"link\"\n  const tabindex = isAnchor ? undefined : 0\n\n  const classes = linkClasses({ variant, class: className })\n\n  return (\n    <Tag\n      id={props.id}\n      href={isAnchor ? href : undefined}\n      target={isAnchor ? resolvedTarget : undefined}\n      rel={isAnchor ? resolvedRel : undefined}\n      role={resolvedRole}\n      tabindex={tabindex}\n      // APG fallback: href is invalid on a non-anchor, so the browser won't\n      // navigate (APG link/examples/link.html). Pass the destination through as\n      // data-href so site.js can wire Enter/click on [role=link][data-href].\n      data-href={!isAnchor ? href : undefined}\n      data-slot=\"link\"\n      data-variant={variant ?? \"default\"}\n      data-external={external ? \"true\" : undefined}\n      class={classes}\n      aria-label={ariaLabel}\n      aria-labelledby={ariaLabelledby}\n      aria-describedby={ariaDescribedby}\n      aria-current={ariaCurrent}\n      {...rest}\n    >\n      {children}\n      {/* External-link glyph. aria-hidden — the SR-only text carries the\n          meaning for assistive tech (MDN \"External links\" guidance). */}\n      {external && (\n        <svg\n          xmlns=\"http://www.w3.org/2000/svg\"\n          viewBox=\"0 0 24 24\"\n          fill=\"none\"\n          stroke=\"currentColor\"\n          stroke-width=\"2\"\n          stroke-linecap=\"round\"\n          stroke-linejoin=\"round\"\n          aria-hidden=\"true\"\n        >\n          <path d=\"M7 17 17 7\" />\n          <path d=\"M7 7h10v10\" />\n        </svg>\n      )}\n      {external && <span class=\"sr-only\"> (opens in new tab)</span>}\n    </Tag>\n  )\n}\n"
    },
    {
      "path": "registry/jinja2/link.html",
      "type": "registry:file",
      "target": "templates/components/link.html",
      "content": "{# Link macro — shadcn-htmx, htmx v4 + Tailwind v4.\n   Mirrors registry/ui/link.tsx. Renders a native <a href> — the WAI-ARIA APG\n   Link pattern (repos/aria-practices/content/patterns/link/link-pattern.html)\n   \"strongly encourages\" a real <a>, so role=link and Enter activation come\n   from the platform.\n\n   Usage:\n     {% from \"components/link.html\" import link %}\n     {{ link(\"Documentation\", href=\"/docs\") }}\n     {{ link(\"Settings\", href=\"/settings\", variant=\"hover\") }}\n     {{ link(\"htmx.org\", href=\"https://htmx.org\", external=true) }}\n\n   external=true sets target=\"_blank\" rel=\"noopener noreferrer\" and appends the\n   \"opens in new tab\" icon + visually-hidden text (MDN: External links).\n\n   as=\"span\"/\"button\" + role=\"link\" is the APG fallback for markup that cannot\n   be an <a>; you must wire navigation yourself. Prefer the native <a>. #}\n\n{% macro link(\n    text,\n    href=none,\n    variant=\"default\",\n    external=false,\n    target=none,\n    rel=none,\n    as=\"a\",\n    id=none,\n    aria_label=none,\n    aria_labelledby=none,\n    aria_describedby=none,\n    aria_current=none,\n    extra_class=\"\",\n    **attrs\n) %}\n{%- set base -%}\ninline-flex items-center gap-1 rounded-sm font-medium text-primary underline-offset-4 transition-colors outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 [&[role=link]]:cursor-pointer [&>svg]:pointer-events-none [&>svg]:size-3.5 [&>svg]:shrink-0\n{%- endset -%}\n{%- set variants = {\n    \"default\": \"underline decoration-primary/40 hover:decoration-primary\",\n    \"muted\": \"text-muted-foreground underline decoration-muted-foreground/40 hover:text-foreground hover:decoration-foreground\",\n    \"hover\": \"no-underline hover:underline\"\n} -%}\n{%- set is_anchor = (as == \"a\") -%}\n{%- set resolved_target = target if target is not none else (\"_blank\" if external else none) -%}\n{%- set resolved_rel = rel if rel is not none else (\"noopener noreferrer\" if external else none) -%}\n<{{ as }}\n  {%- if id %} id=\"{{ id }}\"{% endif %}\n  {%- if is_anchor and href %} href=\"{{ href }}\"{% endif %}\n  {%- if is_anchor and resolved_target %} target=\"{{ resolved_target }}\"{% endif %}\n  {%- if is_anchor and resolved_rel %} rel=\"{{ resolved_rel }}\"{% endif %}\n  {#- APG fallback: href is invalid on a non-anchor; expose it as data-href so\n      site.js can navigate [role=link][data-href] (link/examples/link.html). #}\n  {%- if not is_anchor %} role=\"link\" tabindex=\"0\"{% if href %} data-href=\"{{ href }}\"{% endif %}{% endif %}\n  data-slot=\"link\"\n  data-variant=\"{{ variant }}\"\n  {%- if external %} data-external=\"true\"{% endif %}\n  class=\"{{ base }} {{ variants[variant] }} {{ extra_class }}\"\n  {%- if aria_label %} aria-label=\"{{ aria_label }}\"{% endif %}\n  {%- if aria_labelledby %} aria-labelledby=\"{{ aria_labelledby }}\"{% endif %}\n  {%- if aria_describedby %} aria-describedby=\"{{ aria_describedby }}\"{% endif %}\n  {%- if aria_current %} aria-current=\"{{ aria_current }}\"{% endif %}\n  {%- for k, v in attrs.items() %} {{ k|replace('_', '-') }}=\"{{ v }}\"{% endfor -%}\n>{{ text }}{% if external %}<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M7 17 17 7\"/><path d=\"M7 7h10v10\"/></svg><span class=\"sr-only\"> (opens in new tab)</span>{% endif %}</{{ as }}>\n{% endmacro %}\n"
    },
    {
      "path": "registry/go-templates/link.tmpl",
      "type": "registry:file",
      "target": "components/link.tmpl",
      "content": "{{/*\n  Link template — shadcn-htmx, htmx v4 + Tailwind v4.\n  Mirrors registry/ui/link.tsx. Emits a native <a href>, so the WAI-ARIA APG\n  Link pattern's keyboard contract (Enter activates) and the implicit link\n  role come from the platform. See\n  repos/aria-practices/content/patterns/link/link-pattern.html.\n\n  Usage:\n\n      type LinkArgs struct {\n          Text     string\n          Href     string\n          Variant  string // default | muted | hover\n          External bool   // target=_blank rel=\"noopener noreferrer\" + icon\n          Target   string\n          Rel      string\n          As       string // \"a\" (default) | \"span\" | \"button\"  (role=link fallback)\n          ID       string\n          AriaLabel      string\n          AriaLabelledby string\n          AriaDescribedby string // id of an element describing the link\n          AriaCurrent    string // page | step | location | date | time | true | false\n          Body     template.HTML // optional rich body; falls back to .Text\n          Attrs    map[string]string // hx-*, download, etc.\n      }\n\n      tpl.ExecuteTemplate(w, \"link\", LinkArgs{\n          Text: \"Documentation\", Href: \"/docs\",\n      })\n\n  external=true follows MDN \"External links\" guidance: visible icon + SR-only\n  \"(opens in new tab)\" text.\n*/}}\n\n{{define \"link\"}}\n{{- $variant := or .Variant \"default\" -}}\n{{- $as := or .As \"a\" -}}\n{{- $isAnchor := eq $as \"a\" -}}\n{{- $base := \"inline-flex items-center gap-1 rounded-sm font-medium text-primary underline-offset-4 transition-colors outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 [&[role=link]]:cursor-pointer [&>svg]:pointer-events-none [&>svg]:size-3.5 [&>svg]:shrink-0\" -}}\n{{- $variants := dict\n    \"default\" \"underline decoration-primary/40 hover:decoration-primary\"\n    \"muted\" \"text-muted-foreground underline decoration-muted-foreground/40 hover:text-foreground hover:decoration-foreground\"\n    \"hover\" \"no-underline hover:underline\" -}}\n{{- $target := .Target -}}\n{{- if and .External (eq $target \"\")}}{{$target = \"_blank\"}}{{end -}}\n{{- $rel := .Rel -}}\n{{- if and .External (eq $rel \"\")}}{{$rel = \"noopener noreferrer\"}}{{end -}}\n<{{$as}}\n  {{- if .ID}} id=\"{{.ID}}\"{{end}}\n  {{- if and $isAnchor .Href}} href=\"{{.Href}}\"{{end}}\n  {{- if and $isAnchor $target}} target=\"{{$target}}\"{{end}}\n  {{- if and $isAnchor $rel}} rel=\"{{$rel}}\"{{end}}\n  {{- /* APG fallback: href is invalid on a non-anchor; expose it as data-href so\n         site.js can navigate [role=link][data-href] (link/examples/link.html). */ -}}\n  {{- if not $isAnchor}} role=\"link\" tabindex=\"0\"{{if .Href}} data-href=\"{{.Href}}\"{{end}}{{end}}\n  data-slot=\"link\" data-variant=\"{{$variant}}\"\n  {{- if .External}} data-external=\"true\"{{end}}\n  class=\"{{$base}} {{index $variants $variant}}\"\n  {{- if .AriaLabel}} aria-label=\"{{.AriaLabel}}\"{{end}}\n  {{- if .AriaLabelledby}} aria-labelledby=\"{{.AriaLabelledby}}\"{{end}}\n  {{- if .AriaDescribedby}} aria-describedby=\"{{.AriaDescribedby}}\"{{end}}\n  {{- if .AriaCurrent}} aria-current=\"{{.AriaCurrent}}\"{{end}}\n  {{- range $k, $v := .Attrs}} {{$k}}=\"{{$v}}\"{{end -}}\n>{{if .Body}}{{htmlSafe .Body}}{{else}}{{.Text}}{{end}}{{if .External}}<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M7 17 17 7\"/><path d=\"M7 7h10v10\"/></svg><span class=\"sr-only\"> (opens in new tab)</span>{{end}}</{{$as}}>\n{{end}}\n"
    },
    {
      "path": "registry/phoenix/link.ex",
      "type": "registry:file",
      "target": "lib/my_app_web/components/link.ex",
      "content": "defmodule ShadcnHtmx.Components.Link do\n  @moduledoc \"\"\"\n  Link — shadcn-htmx, htmx v4 + Tailwind v4 for Phoenix.\n\n  Mirrors registry/ui/link.tsx. Renders a native `<a href>`, which the\n  WAI-ARIA APG Link pattern \"strongly encourages\" over a faked role=link\n  element — see\n  repos/aria-practices/content/patterns/link/link-pattern.html. The native\n  anchor gives us the implicit `link` role and Enter-activates-the-link\n  keyboard behaviour with no JavaScript.\n\n  ## Examples\n\n      <.link_ href=\"/docs\">Documentation</.link_>\n      <.link_ href=\"/settings\" variant=\"hover\">Settings</.link_>\n      <.link_ href=\"https://htmx.org\" external>htmx.org</.link_>\n\n  `external` sets `target=\"_blank\" rel=\"noopener noreferrer\"` and appends the\n  \"opens in new tab\" icon + visually-hidden text (MDN: External links).\n\n  `as=\"span\"`/`\"button\"` renders the APG role=link fallback for markup that\n  cannot be an `<a>`; you must wire navigation yourself. Prefer the native\n  `<a>`.\n\n  The function is named `link_` to avoid clashing with Phoenix.Component's\n  built-in `link/1`.\n  \"\"\"\n\n  use Phoenix.Component\n\n  @base \"inline-flex items-center gap-1 rounded-sm font-medium text-primary underline-offset-4 transition-colors outline-none \" <>\n          \"focus-visible:ring-[3px] focus-visible:ring-ring/50 \" <>\n          \"[&[role=link]]:cursor-pointer \" <>\n          \"[&>svg]:pointer-events-none [&>svg]:size-3.5 [&>svg]:shrink-0\"\n\n  @variants %{\n    \"default\" => \"underline decoration-primary/40 hover:decoration-primary\",\n    \"muted\" =>\n      \"text-muted-foreground underline decoration-muted-foreground/40 hover:text-foreground hover:decoration-foreground\",\n    \"hover\" => \"no-underline hover:underline\"\n  }\n\n  attr :variant, :string, default: \"default\", values: ~w(default muted hover)\n  attr :href, :string, default: nil\n  attr :external, :boolean, default: false\n  attr :target, :string, default: nil\n  attr :rel, :string, default: nil\n  attr :as, :string, default: \"a\", values: ~w(a span button)\n  attr :class, :string, default: nil\n\n  attr :rest, :global,\n    include:\n      ~w(hx-get hx-target hx-swap hx-boost hx-push-url\n         download hreflang referrerpolicy ping type\n         id aria-label aria-labelledby aria-describedby aria-current)\n\n  slot :inner_block, required: true\n\n  # APG fallback: href is invalid on a non-anchor element, so the browser will\n  # not navigate (link/examples/link.html). We expose the destination as\n  # data-href below so site.js can wire Enter/click on [role=link][data-href].\n  def link_(assigns) do\n    is_anchor = assigns.as == \"a\"\n    target = assigns.target || if(assigns.external, do: \"_blank\")\n    rel = assigns.rel || if(assigns.external, do: \"noopener noreferrer\")\n\n    assigns =\n      assigns\n      |> assign(:variant_class, Map.fetch!(@variants, assigns.variant))\n      |> assign(:base_class, @base)\n      |> assign(:is_anchor, is_anchor)\n      |> assign(:resolved_target, if(is_anchor, do: target))\n      |> assign(:resolved_rel, if(is_anchor, do: rel))\n\n    ~H\"\"\"\n    <.dynamic_tag\n      tag_name={@as}\n      href={if @is_anchor, do: @href}\n      target={@resolved_target}\n      rel={@resolved_rel}\n      role={if !@is_anchor, do: \"link\"}\n      tabindex={if !@is_anchor, do: \"0\"}\n      data-href={if !@is_anchor, do: @href}\n      data-slot=\"link\"\n      data-variant={@variant}\n      data-external={if @external, do: \"true\"}\n      class={[@base_class, @variant_class, @class]}\n      {@rest}\n    >\n      {render_slot(@inner_block)}<svg\n        :if={@external}\n        xmlns=\"http://www.w3.org/2000/svg\"\n        viewBox=\"0 0 24 24\"\n        fill=\"none\"\n        stroke=\"currentColor\"\n        stroke-width=\"2\"\n        stroke-linecap=\"round\"\n        stroke-linejoin=\"round\"\n        aria-hidden=\"true\"\n      ><path d=\"M7 17 17 7\" /><path d=\"M7 7h10v10\" /></svg><span :if={@external} class=\"sr-only\"> (opens in new tab)</span>\n    </.dynamic_tag>\n    \"\"\"\n  end\nend\n"
    },
    {
      "path": "registry/html/link.html",
      "type": "registry:file",
      "target": "snippets/link.html",
      "content": "<!--\n  shadcn-htmx — raw HTML link snippets.\n\n  No template engine, no JavaScript framework. Just a native <a href> with the\n  class strings you need, ready to drop into any HTML file that loads\n  Tailwind CSS v4.\n\n  Why a real <a>? The WAI-ARIA APG Link pattern strongly encourages the native\n  element: role=link and Enter-to-activate come from the browser, and you keep\n  open-in-new-tab, copy-link, and the context menu — all of which break when\n  you fake a link with role=link on a <span>. See\n  repos/aria-practices/content/patterns/link/link-pattern.html.\n\n  Requirements:\n    1. Tailwind CSS v4 (or the Play CDN for quick experiments).\n    2. The shadcn CSS variables (--primary, --muted-foreground, --ring, …).\n       Copy the :root / .dark blocks from app/styles/input.css.\n\n  BASE (shared by every variant):\n    inline-flex items-center gap-1 rounded-sm font-medium text-primary\n    underline-offset-4 transition-colors outline-none\n    focus-visible:ring-[3px] focus-visible:ring-ring/50\n    [&[role=link]]:cursor-pointer\n    [&>svg]:pointer-events-none [&>svg]:size-3.5 [&>svg]:shrink-0\n-->\n\n<!-- ─── Variants ────────────────────────────────────────────────────── -->\n\n<!-- default — underlined, primary colour; reads as a link in prose -->\n<a href=\"/docs\" data-slot=\"link\" data-variant=\"default\"\n  class=\"inline-flex items-center gap-1 rounded-sm font-medium text-primary underline-offset-4 transition-colors outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 [&[role=link]]:cursor-pointer [&>svg]:pointer-events-none [&>svg]:size-3.5 [&>svg]:shrink-0 underline decoration-primary/40 hover:decoration-primary\">\n  Documentation\n</a>\n\n<!-- muted — low-emphasis inline link -->\n<a href=\"/changelog\" data-slot=\"link\" data-variant=\"muted\"\n  class=\"inline-flex items-center gap-1 rounded-sm font-medium text-primary underline-offset-4 transition-colors outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 [&[role=link]]:cursor-pointer [&>svg]:pointer-events-none [&>svg]:size-3.5 [&>svg]:shrink-0 text-muted-foreground underline decoration-muted-foreground/40 hover:text-foreground hover:decoration-foreground\">\n  Changelog\n</a>\n\n<!-- hover — no underline at rest, underline on hover/focus; nav / menu link -->\n<a href=\"/settings\" data-slot=\"link\" data-variant=\"hover\"\n  class=\"inline-flex items-center gap-1 rounded-sm font-medium text-primary underline-offset-4 transition-colors outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 [&[role=link]]:cursor-pointer [&>svg]:pointer-events-none [&>svg]:size-3.5 [&>svg]:shrink-0 no-underline hover:underline\">\n  Settings\n</a>\n\n<!-- ─── External (opens in new tab) ─────────────────────────────────── -->\n<!--\n  target=\"_blank\" implicitly behaves like rel=\"noopener\" in modern browsers;\n  we still write rel=\"noopener noreferrer\" so it's explicit. The icon is\n  aria-hidden; the SR-only span tells screen-reader users what will happen.\n-->\n<a href=\"https://htmx.org\" target=\"_blank\" rel=\"noopener noreferrer\"\n  data-slot=\"link\" data-variant=\"default\" data-external=\"true\"\n  class=\"inline-flex items-center gap-1 rounded-sm font-medium text-primary underline-offset-4 transition-colors outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 [&[role=link]]:cursor-pointer [&>svg]:pointer-events-none [&>svg]:size-3.5 [&>svg]:shrink-0 underline decoration-primary/40 hover:decoration-primary\">\n  htmx.org\n  <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n    <path d=\"M7 17 17 7\" /><path d=\"M7 7h10v10\" />\n  </svg>\n  <span class=\"sr-only\"> (opens in new tab)</span>\n</a>\n\n<!-- ─── In prose ────────────────────────────────────────────────────── -->\n<p class=\"text-sm text-muted-foreground\">\n  Learn more\n  <a href=\"/docs/link\" data-slot=\"link\" data-variant=\"default\"\n    class=\"inline-flex items-center gap-1 rounded-sm font-medium text-primary underline-offset-4 transition-colors outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 [&>svg]:pointer-events-none [&>svg]:size-3.5 [&>svg]:shrink-0 underline decoration-primary/40 hover:decoration-primary\">about links</a>.\n</p>\n\n<!-- ─── APG fallback (only when an <a> is impossible) ───────────────── -->\n<!--\n  The APG link examples (link/examples/link.html) use a <span> with\n  role=\"link\" + tabindex=\"0\" + a keydown handler ONLY when the element cannot\n  be an anchor. The platform does NOT navigate for you here — wire it up with\n  JS. This is the exception, not the rule. Prefer the native <a> above.\n-->\n<span role=\"link\" tabindex=\"0\" data-slot=\"link\" data-variant=\"default\"\n  data-href=\"/docs\"\n  class=\"inline-flex items-center gap-1 rounded-sm font-medium text-primary underline-offset-4 transition-colors outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 [&[role=link]]:cursor-pointer underline decoration-primary/40 hover:decoration-primary\">\n  Span pretending to be a link\n</span>\n\n<script>\n  // Minimal boot for the role=link fallback only. Native <a href> needs none\n  // of this. Mirrors the APG example contract: Enter activates the link.\n  (function () {\n    function go(el) {\n      var href = el.getAttribute(\"data-href\")\n      if (href) window.location.href = href\n    }\n    document.querySelectorAll('[data-slot=\"link\"][role=\"link\"]').forEach(function (el) {\n      el.addEventListener(\"click\", function () { go(el) })\n      el.addEventListener(\"keydown\", function (e) {\n        if (e.key === \"Enter\") { e.preventDefault(); go(el) }\n      })\n    })\n  })()\n</script>\n"
    }
  ]
}
