Link
汎用のインラインリンク(a 要素 1 パーツ)です。fandhe-frontend-headless-ui の link mod が構造・アクセシビリティ(WAI-ARIA・キーボード操作)・表示状態(data-*)のみを提供する unstyled 部品であり、Themes 版と異なりスタイル(CSS)は一切持ちません。root(a)1 パーツのみで、時間変化する内部状態を持たないため data-current 以外の状態語彙は一切出力しません。external を true にすると target="_blank" と rel="noopener noreferrer" を不可分に付与し、reverse tabnabbing を防ぎます。
スタイル済みの表示例は Link を参照してください。
キーボード操作
| キー | 対象 | 効果 |
|---|---|---|
| Tab / Shift+Tab | Root | ネイティブ a[href] へのフォーカス移動です(ブラウザ既定、headless-ui 側の配線なし)。 |
| Enter | Root | ネイティブ a[href] の起動(遷移)です。Space はリンクを起動しません(<a> 要素は Space キーでは発火しないブラウザ標準挙動です)。 |
参考サイトとの差分
chakra-ui の Link(variant/colorPalette/asChild のみを持つ styled a)・Radix Themes の Link(size/weight/underline/color/highContrast/asChild 等のスタイル prop のみを持つ styled a)はいずれも Anatomy 節・Keyboard Interactions 節・data-* 語彙を持ちません(ark-ui・Radix Primitives には Link 相当のコンポーネント自体が存在しません)。本実装は以下の点で意図的に差分を残しています。
data-scope/data-part/data-current: 参考サイトには anatomy の概念自体が無く、本実装のこれらの属性はこちら側の superset です。externalのtarget+rel不可分付与: 参考実装は生のtarget/rel属性を利用者が渡す設計ですが、本実装はexternal引数の true/false のみで両属性をまとめて出力/省略し、片方だけを付与できる API を公開しません(reverse tabnabbing 対策を API 側で保証する意図的差分)。- 非対応の prop:
asChild(Slot 相当)・variant・colorPalette・size・underline・highContrast・truncate・wrap・trimはいずれも非対応です。asChildは headless-ui 全体での再導入検討事項(保留)であり、装飾軸(variant以下)は Themes 層pre-styled-ui::link(/themes/link/)の責務です。 disabledの非提供:a要素にはネイティブの disabled 意味論が無く、参考サイトもdisabledを提供しません。無効状態が必要な場合は、呼び出し側でlink::rootの呼び出し自体を止め、非操作要素へ描画を差し替えてください。
一方で「role/aria-* を独自付与しない(暗黙の link ロールに委ねる)」点は参考サイトと一致しています。危険な URL スキーム(javascript: 等)は href 属性ごと拒否され、href を失った a はフォーカス不能になり暗黙の link ロールも失います(fail-closed の意味論的帰結)。
関連 API: fandhe-frontend-headless-ui API
自前 CSS の最小例
Themes 版を使わず本部品を直接使う場合、[data-scope="link"][data-part="root"] セレクタと :hover・:focus-visible・[aria-current="page"] 擬似クラス/属性セレクタでスタイルを当てます。
[data-scope="link"][data-part="root"] {
color: #2563eb;
text-decoration: none;
}
[data-scope="link"][data-part="root"]:hover {
text-decoration: underline;
}
[data-scope="link"][data-part="root"]:focus-visible {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
[data-scope="link"][data-part="root"][aria-current="page"] {
color: #111827;
font-weight: 600;
text-decoration: none;
}
[data-scope="link"][data-part="root"][target="_blank"]::after {
content: " ↗";
}Demo
枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。
Features
- 汎用インラインリンク。root(a)1 パーツのみの最小構成(chakra-ui Link 相当、link.rs モジュール doc)。
- external=true のとき target="_blank"+rel="noopener noreferrer" を不可分に付与する(reverse tabnabbing 対策。片方のみを付与できる API は公開しない)。参考サイト(chakra-ui)は生の target/rel を利用者が渡す設計であり、本実装は API 側で不可分付与を保証する意図的差分。
- current=true のとき aria-current="page"+data-current を付与する(breadcrumb/nav_list と同じ語彙を共有)。
- data-state/data-disabled/data-motion 等の状態 data-* は出力しない(§3.25 規則 2: 装飾・アニメーション関心を headless へ持ち込まない)。
- asChild(Slot 相当)・variant/colorPalette/size/underline/highContrast 等の装飾軸は本モジュールでは提供しない。asChild は intentional-non-adoption.md §3.25 表 Slot 行の保留により非採用、装飾軸は Themes 層 pre-styled-ui::link(/themes/link/)の責務。
Anatomy
rootAPI Reference
Arguments
| Name | Type | Default | Description |
|---|---|---|---|
root(href) | &str | — | 遷移先 URL。危険な URL スキーム(javascript: 等)は core の render() が属性ごと拒否する。 |
root(external) | bool | — | true のとき target="_blank"+rel="noopener noreferrer" を不可分に付与する。 |
root(current) | bool | — | true のとき aria-current="page"+data-current を付与する。 |
Data Attributes
| Part | Attribute | Observed Values |
|---|---|---|
root | data-current | (値なし) |
Examples
external=false, current=false の構成
external/current をともに false にして target="_blank"/rel/aria-current/data-current のいずれも出力しない最小構成です。
current=true の構成
current を true にして aria-current="page" と data-current を同時に出力する構成です。
文中インライン
段落テキストの中にリンクを混在させても anatomy 出力・エスケープが変わらないことを示す構成です。
See the guide for setup steps.
自前 CSS の最小例
data-scope/data-part/[aria-current="page"] 属性セレクタで自前 CSS を当てる最小例です。headless-ui 自体はスタイルを持ちません。
[data-scope="link"][data-part="root"] {
color: #2563eb;
text-decoration: none;
}
[data-scope="link"][data-part="root"]:hover {
text-decoration: underline;
}
[data-scope="link"][data-part="root"]:focus-visible {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
[data-scope="link"][data-part="root"][aria-current="page"] {
color: #111827;
font-weight: 600;
text-decoration: none;
}
[data-scope="link"][data-part="root"][target="_blank"]::after {
content: " ↗";
}
Accessibility
Keyboard Interactions
| Key | Description |
|---|---|
| Tab / Shift+Tab | ネイティブ要素(a[href])由来のフォーカス移動(ブラウザ既定、headless-ui 側の配線なし)。 |
| Enter | ネイティブ a[href] 由来の起動(リンク先へ遷移)。Space は起動しない(ブラウザ既定の a 要素の挙動)。 |
WAI-ARIA
| Attribute | Description |
|---|---|
| role / aria-* | 既定では付与しない。暗黙の link ロールに委ねる(参考サイトも独自付与しない)。 |
| aria-current="page" | current 引数が true のときのみ data-current と同時に付与する。 |
| rel="noopener noreferrer" | ARIA ではないがセキュリティ属性として併記する。external 引数が true のとき target="_blank" と同時に付与する。 |
| (危険スキーム時) | javascript: 等の危険な URL スキームは core の render() が href 属性ごと拒否する。href を失った a はフォーカス不能になり、暗黙の link ロールも失う(fail-closed の意味論的帰結)。 |