Skip to content
fandhe-frontendcore v0.4.3
GitHub

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 / EnterTrigger / ItemDeleteTrigger / ClearTriggerいずれもネイティブ <button> であるため、ブラウザ標準の活性化操作が働きます
Space / EnterDropzone参照実装(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 の最小例です。

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: " *";
}

Demo

枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。

Default(受理済み + 拒否済みファイル各 1 件)

Drag files here or
  • photo.png
    200.0 KB
  • malware.exe
    10.0 KB

Disabled

Drag files here or

      Readonly + Invalid + Required

      Drag files here or

          Dragging(data-dragging)

          Drag files here or

              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-trigger

              API Reference

              Arguments

              NameTypeDefaultDescription
              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 / childrenVec<(&str, &str)> / Vec<Node>—各パーツ共通の追加属性・子ノード(代表 1 行に集約)。

              Data Attributes

              PartAttributeObserved Values
              clear-triggerdata-disabled(値なし)
              clear-triggerdata-readonly(値なし)
              dropzonedata-disabled(値なし)
              dropzonedata-dragging(値なし)
              dropzonedata-invalid(値なし)
              dropzonedata-readonly(値なし)
              hidden-inputdata-disabled(値なし)
              hidden-inputdata-readonly(値なし)
              hidden-inputdata-required(値なし)
              itemdata-typeaccepted, rejected
              item-delete-triggerdata-typeaccepted, rejected
              item-groupdata-disabled(値なし)
              item-groupdata-readonly(値なし)
              item-groupdata-typeaccepted, rejected
              item-namedata-typeaccepted, rejected
              item-size-textdata-typeaccepted, rejected
              labeldata-disabled(値なし)
              labeldata-invalid(値なし)
              labeldata-readonly(値なし)
              labeldata-required(値なし)
              rootdata-disabled(値なし)
              rootdata-dragging(値なし)
              rootdata-invalid(値なし)
              rootdata-readonly(値なし)
              triggerdata-disabled(値なし)
              triggerdata-invalid(値なし)
              triggerdata-readonly(値なし)

              Examples

              Single file dropzone

              PDF のみを受け付ける単一ファイル選択の例です。

              role="button" のドロップゾーンと単一ファイル選択 hidden_input の組み立て例です。

              Drag & drop or

              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

              KeyDescription
              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

              AttributeDescription
              role="button"dropzone パーツへ固定付与する。
              aria-labeldropzone パーツへ既定値 "dropzone"(呼び出し側指定が無いときのみ)、item_delete_trigger パーツへ「Delete {name}」を動的に組み立てて付与する。
              aria-disabled="true"dropzone パーツへ disabled または readonly のときに付与する。
              aria-hidden="true"hidden_input パーツへ固定付与する(フォーカス・スクリーンリーダー走査の対象外にする)。
              aria-requiredhidden_input パーツへ props.required の値をそのまま反映する(true/false の明示 2 値、ネイティブ required は出力しない)。