Download Trigger
a[download] 属性による宣言的なファイルダウンロードトリガーです。Blob 生成のような JS 実行を必要とせず、プレーンな HTML のみで完結する静的部品として実装されています。root(a[href][download])1 パーツのみの最小構成で、時間変化する内部状態を持たないため data-* の状態語彙は一切出力しません。
Themes 版(/themes/download-trigger/)は Button recipe を流用した既定 CSS を追加する薄いラッパーであり、本 Primitives 部品自体は CSS を一切持ちません。スタイル済みの表示例は Download Trigger を参照してください。
キーボード操作
| キー | 対象 | 効果 |
|---|---|---|
| Tab | Root | ネイティブ a[href] へのフォーカス移動です。 |
| Enter | Root | ネイティブ a[href] の起動(ダウンロード開始)です。Space はリンクを起動しません(<a> 要素は Space キーでは発火しないブラウザ標準挙動です)。 |
参考サイトとの差分
ark-ui / chakra-ui の DownloadTrigger は Blob 生成・非同期データ解決を行う JS ユーティリティで、<button type="button">(chakra は asChild で任意要素へ差し替え可能)を起点とし、Anatomy 節・Accessibility 節を持ちません(data-* 状態語彙も ARIA 属性の付与もありません)。本実装は以下の点で意図的に差分を残しています。
- 要素種別: 参考サイトの
buttonに対し、本実装はa[href][download]を採用します(プレーンな HTML を尊重する静的部品化方針)。この差により、参考サイトでは効く Space キーでの起動が本実装では効きません(上記キーボード操作表参照)。 data-scope/data-part: 参考サイトには anatomy の概念自体が無く、本実装のdata-scope="download-trigger"/data-part="root"はこちら側の superset です。- 非対応の prop:
data(Blob/ArrayBuffer/非同期関数)・mimeType・asChildは非対応です。Blob生成はクライアント JS 前提であり静的部品化方針の対象外、実ファイル配信時のContent-Typeは配信側ヘッダで表現します。 disabledの非提供:a要素にはネイティブの disabled 意味論がなく、rootは常にhref属性を出力するため、呼び出し側attrsでaria-disabled="true"+tabindex="-1"を付与してもクリック(および Enter キー)でのダウンロード起動は実際には防げません(aria-disabledは状態を伝えるだけ、tabindex="-1"は Tab 移動対象から外すだけで、hrefを保持したままのaはブラウザ標準動作としてクリック起動可能です)。無効状態が必要な場合は、呼び出し側でdownload_trigger::rootの呼び出し自体を止め、非操作要素(span/disabledなbutton等)へ描画を差し替えてください。- cross-origin での
download無視: ブラウザ仕様上、download属性は same-origin(およびblob:/data:)以外のリンクでは無視され、通常のナビゲーションとして扱われます。
一方で「状態を表す data-* を出力しない」「role/aria-* を独自付与しない」点は参考サイトと一致しています。
関連 API: fandhe-frontend-headless-ui API
自前 CSS の最小例
Themes 版を使わず本部品を直接使う場合、[data-scope="download-trigger"][data-part="root"] セレクタと :focus-visible 擬似クラスでスタイルを当てます。状態を表す data-* が無いため、当てられるセレクタはこの 2 種類のみです。
[data-scope="download-trigger"][data-part="root"] {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.5rem 0.875rem;
border: 1px solid #888;
border-radius: 6px;
text-decoration: none;
}
[data-scope="download-trigger"][data-part="root"]:focus-visible {
outline: 2px solid #2563eb;
outline-offset: 2px;
}Demo
枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。
Features
- Root(
a[download])1 パーツのみの最小構成。href/file_nameからdownload属性を組み立てる宣言的トリガーであり、JS(Blob生成・非同期データ解決)を必要としない静的部品として実装される(AI 時代のセキュリティリスク低減方針に基づく意図的な設計)。 hrefはfandhe_frontend_core::renderの既定エスケープ経路(許可スキームのみを通す deny-by-default)を通り、javascript:/data:/blob:/vbscript:等の危険なスキームは属性ごと出力されない(fail-closed)。file_nameがSome(name)のときdownload="<name>"、Noneのときdownload=""(配信元のファイル名を使うブラウザ既定挙動)を出力する。- 実際のファイル取得(
Blob/非同期データ解決)・mimeTypeの指定は非対応。実ファイル配信時のContent-Typeは配信側ヘッダで表現する。 - ark-ui/chakra-ui の DownloadTrigger は
<button type="button">を起点とする JS ユーティリティで anatomy・data-*状態語彙・ARIA を一切持たない(Anatomy/Accessibility 節が存在しない)。本実装はa[download]へdata-scope/data-partを付けた静的 superset であり、data-state/data-disabled/data-motion等は出さない(docs/policy/intentional-non-adoption.md§3.25 規則 2)。 - 参考実装の
asChild(Slot 相当の要素差し替え)は非採用(同ポリシー §3.25 表 Slot 行)。要素種別もbuttonではなくa[href]を採用する意図的差分。
Anatomy
rootAPI Reference
Arguments
| Name | Type | Default | Description |
|---|---|---|---|
href | &str | (必須) | 配信 URL。危険なスキームは render() の既定エスケープ経路で属性ごと出力されない。 |
file_name | Option<&str> | None | Some(name) で download="<name>"、None で download=""。 |
Examples
file_name を省略した変種
file_name に None を渡すと download="" が出力され、ブラウザは配信元のファイル名をそのまま使用します。
自前 CSS の最小例
data-scope / data-part 属性セレクタと :focus-visible 擬似クラスで見た目を組み立てる最小例です。headless-ui 自体はスタイルを持ちません。
[data-scope="download-trigger"][data-part="root"] {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.5rem 0.875rem;
border: 1px solid #888;
border-radius: 6px;
text-decoration: none;
}
[data-scope="download-trigger"][data-part="root"]:focus-visible {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
Accessibility
Keyboard Interactions
| Key | Description |
|---|---|
| Tab | root(a[href])へフォーカスを移動する(ブラウザ既定動作)。 |
| Enter | ネイティブ a[href] の起動(ダウンロード開始)。Space はリンクを起動しない(button を採用する参考サイトは Enter/Space の双方が効く点が意図的差分)。 |
WAI-ARIA
| Attribute | Description |
|---|---|
| role / aria-* | 付与しない(a[href] の暗黙 link ロールに委ねる。参考サイトも role/aria-* を付与しない)。呼び出し側 attrs で aria-disabled="true" + tabindex="-1" を渡しても href は保持されクリック起動は防げないため(a に disabled 意味論はない)、無効状態が必要な場合は root の呼び出し自体を止め非操作要素へ差し替える(site/primitives/download-trigger.md 参照)。 |