File Upload
ドロップゾーン・ボタン起点のファイル選択・受理済みファイル一覧を持つアップロード部品です。ファイルメタデータ(ファイル名・サイズ・MIME タイプ)のみを扱い、File オブジェクト自体や実際のアップロード処理は保持しません(accept/max-files 等の検証は決定的な純粋関数で行いますが、実送信・保存は利用者側の責務です)。
fandhe-frontend-headless-ui の file_upload mod が提供する構造・アクセシビリティ(WAI-ARIA・キーボード操作)・表示状態(data-*)のみを持つ unstyled 部品です。Themes 版が備える見た目は持たず、anatomy・ARIA・data-* のみを提供します。CSS は利用者が当てます。
FileUploadProps(disabled/readonly/invalid/required)が Root/Label/Dropzone/Trigger/ClearTrigger/HiddenInput へ data-disabled/data-readonly/data-invalid を一律付与し、Label のみ追加で data-required を付与します。Dropzone は disabled または readonly のとき tabindex="-1" + aria-disabled="true"、それ以外は tabindex="0" になり、呼び出し側 attrs に aria-label/aria-labelledby が無ければ既定 aria-label="dropzone" を付与します。Trigger/ItemDeleteTrigger/ClearTrigger/HiddenInput は readonly でもネイティブ disabled を付与します(zag disabled: disabled || readOnly と同値の判断)。HiddenInput には tabindex="-1"・aria-hidden="true"・required(props.required)を追加します。ClearTrigger は hidden 引数(受理済みファイル 0 件を表す)で hidden 属性を出力します。ItemGroup/Item/ItemName/ItemSizeText/ItemDeleteTrigger には ItemType(Accepted/Rejected)固定語彙による data-type を付与します。Item への data-invalid は参照側(zag/ark)も出さないため付与しません(呼び出し側 attrs 経由でのみ有効化できます)。
キーボード操作
| キー | 対象 | 効果 |
|---|---|---|
| Space / Enter | Trigger / ItemDeleteTrigger / ClearTrigger | いずれもネイティブ <button> であるため、ブラウザ標準の活性化操作が働きます |
| Space / Enter | Dropzone | 参照実装(zag)ではこのキー操作でファイル選択ダイアログを起動します。本部品は role="button" + tabindex="0"(disabled/readonly 時は tabindex="-1")の SSR マークアップのみを提供し、fandhe-frontend-wasm-full 側の keydown 配線は未実装です(スコープ外、フォローアップ Issue 提案)。キーボード専用利用者は Trigger(ネイティブ <button>)で操作できるため a11y 上のブロッカーではありません |
ドラッグ&ドロップの実際の DOM 配線(fandhe-frontend-wasm-full)は disabled/readonly いずれの状態でも新規ファイルの追加操作を無視します。
スタイル済みの表示例は File Upload を参照してください。
関連 API: fandhe-frontend-headless-ui API
自前 CSS の最小例
Themes 版を使わず本部品を直接使う場合、[data-scope="file-upload"][data-part="..."] セレクタでスタイルを当てます。以下はドラッグ中の強調表示・disabled trigger・rejected item・required label の最小例です。
[data-scope="file-upload"][data-part="dropzone"][data-dragging] {
border-color: dodgerblue;
}
[data-scope="file-upload"][data-part="trigger"][data-disabled] {
cursor: not-allowed;
}
[data-scope="file-upload"][data-part="item"][data-type="rejected"] {
color: crimson;
}
[data-scope="file-upload"][data-part="label"][data-required]::after {
content: " *";
}Demo
枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。
Default(受理済み + 拒否済みファイル各 1 件)
- photo.png200.0 KB
- malware.exe10.0 KB
Disabled
Readonly + Invalid + Required
Dragging(data-dragging)
Features
- root/label/dropzone/trigger/item_group/item/item_name/item_size_text_node/item_delete_trigger/clear_trigger/hidden_input の 11 anatomy パーツで構成する(file_upload.rs:1-9)。
- FileUploadProps(disabled/readonly/invalid/required)を各パーツへ一律付与する。dropzone は disabled または readonly のとき tabindex="-1" + aria-disabled="true"、それ以外は tabindex="0" にする。呼び出し側 attrs に aria-label/aria-labelledby が無ければ既定 aria-label="dropzone" を付与する(参照突合、イシュー #1609)。
- trigger/item_delete_trigger/clear_trigger/hidden_input は readonly でもネイティブ disabled を付与する(zag disabled: disabled || readOnly と同値)。
- hidden_input には tabindex="-1"・aria-hidden="true"・aria-required/data-required(props.required。ネイティブ required は出力しない。理由: 実 FileList を保持しない設計とネイティブ constraint validation が衝突するため)を付与する。clear_trigger は hidden 引数(受理済みファイル 0 件を表す)で hidden 属性を出力する(イシュー #1609)。
- item_group/item/item_name/item_size_text_node/item_delete_trigger には ItemType(Accepted/Rejected)固定語彙による data-type を付与する。item への data-invalid は参照側(zag/ark)も出さないため付与しない(呼び出し側 attrs 経由でのみ有効化できる)。
- 本モジュールはファイルメタデータ(name/size_bytes/mime_type)のみを保持し、File オブジェクト自体・実アップロード処理は持たない(file_upload.rs:20-27)。
Anatomy
root
label
dropzone
trigger
hidden-input
item-group
item
item-name
item-size-text
item-delete-trigger
clear-triggerAPI Reference
Arguments
| Name | Type | Default | Description |
|---|---|---|---|
root(props, dragging) | &FileUploadProps, bool | — | data-disabled/data-invalid/data-readonly/data-dragging を反映する。 |
label(props) | &FileUploadProps | — | data-required(props.required)を含む状態束を反映する。 |
dropzone(props, dragging) | &FileUploadProps, bool | — | role="button" 固定。disabled/readonly で tabindex="-1" + aria-disabled="true"、既定 aria-label="dropzone"(呼び出し側指定を優先)。 |
trigger(props) / clear_trigger(props, hidden) / hidden_input(accept, multiple, props) | &FileUploadProps 他 | — | readonly でもネイティブ disabled。clear_trigger の hidden は受理済み 0 件で true(FileUpload::clear_trigger が is_empty() から導出)。 |
item_group(item_type, props) / item(item_type, props) / item_name(item_type, props) / item_size_text_node(item_type, props) | ItemType, &FileUploadProps | — | data-type("accepted"/"rejected")を付与する。 |
item_delete_trigger(name, item_type, props) | &str, ItemType, &FileUploadProps | — | aria-label="Delete {name}" を動的に組み立てる(既定エスケープ経由)。 |
attrs / children | Vec<(&str, &str)> / Vec<Node> | — | 各パーツ共通の追加属性・子ノード(代表 1 行に集約)。 |
Data Attributes
| Part | Attribute | Observed Values |
|---|---|---|
clear-trigger | data-disabled | (値なし) |
clear-trigger | data-readonly | (値なし) |
dropzone | data-disabled | (値なし) |
dropzone | data-dragging | (値なし) |
dropzone | data-invalid | (値なし) |
dropzone | data-readonly | (値なし) |
hidden-input | data-disabled | (値なし) |
hidden-input | data-readonly | (値なし) |
hidden-input | data-required | (値なし) |
item | data-type | accepted, rejected |
item-delete-trigger | data-type | accepted, rejected |
item-group | data-disabled | (値なし) |
item-group | data-readonly | (値なし) |
item-group | data-type | accepted, rejected |
item-name | data-type | accepted, rejected |
item-size-text | data-type | accepted, rejected |
label | data-disabled | (値なし) |
label | data-invalid | (値なし) |
label | data-readonly | (値なし) |
label | data-required | (値なし) |
root | data-disabled | (値なし) |
root | data-dragging | (値なし) |
root | data-invalid | (値なし) |
root | data-readonly | (値なし) |
trigger | data-disabled | (値なし) |
trigger | data-invalid | (値なし) |
trigger | data-readonly | (値なし) |
Examples
Single file dropzone
PDF のみを受け付ける単一ファイル選択の例です。
role="button" のドロップゾーンと単一ファイル選択 hidden_input の組み立て例です。
Readonly / invalid / required
readonly + invalid + required を同時に指定した例です。
readonly + invalid + required を同時に指定した例です。label に data-required、dropzone/trigger/hidden_input に tabindex="-1"/aria-disabled/ネイティブ disabled、hidden_input に aria-required/data-required が反映されます(ネイティブ required は出力しません、イシュー #1609)。
Rejected files
検証で拒否されたファイルを ItemType::Rejected で描画する例です。
accept 検証で拒否されたファイルを ItemType::Rejected で描画する例です。item_group/item/item_name/item_delete_trigger のいずれも data-type="rejected" を出力します。
- malware.exe
Custom CSS (headless-ui only)
pre-styled-ui 非依存で自前 CSS を当てる最小例です。
headless-ui 単独利用時(pre-styled-ui 非依存)に、利用者が data-part/data-* セレクタで自前 CSS を当てる最小例です。
[data-scope="file-upload"][data-part="dropzone"][data-dragging] {
border-color: dodgerblue;
}
[data-scope="file-upload"][data-part="trigger"][data-disabled] {
cursor: not-allowed;
}
[data-scope="file-upload"][data-part="item"][data-type="rejected"] {
color: crimson;
}
[data-scope="file-upload"][data-part="label"][data-required]::after {
content: " *";
}Accessibility
Keyboard Interactions
| Key | Description |
|---|---|
| Space / Enter(trigger / item_delete_trigger / clear_trigger) | いずれもネイティブ <button> であるため、ブラウザ標準の活性化操作が働く(file_upload.rs 参照)。 |
| Space / Enter(dropzone) | 参照実装(zag)ではこのキー操作でファイル選択ダイアログを起動する。本モジュールは role="button" + tabindex="0"(disabled/readonly 時は tabindex="-1")の SSR マークアップのみを提供し、fandhe-frontend-wasm-full 側の keydown 配線は未実装(スコープ外、フォローアップ Issue 提案)。キーボード専用利用者は trigger(ネイティブ button)で操作できるため a11y 上のブロッカーではない。 |
WAI-ARIA
| Attribute | Description |
|---|---|
| role="button" | dropzone パーツへ固定付与する。 |
| aria-label | dropzone パーツへ既定値 "dropzone"(呼び出し側指定が無いときのみ)、item_delete_trigger パーツへ「Delete {name}」を動的に組み立てて付与する。 |
| aria-disabled="true" | dropzone パーツへ disabled または readonly のときに付与する。 |
| aria-hidden="true" | hidden_input パーツへ固定付与する(フォーカス・スクリーンリーダー走査の対象外にする)。 |
| aria-required | hidden_input パーツへ props.required の値をそのまま反映する(true/false の明示 2 値、ネイティブ required は出力しない)。 |