FileInput
選ばれたファイルを File として渡すコンポーネント。
読み込むのは呼び出し側の仕事です。音声ファイルなら decodeAudioData、プリセットなら JSON.parse へ。このコンポーネントは、ブラウザがバイト列を渡してきたところで止まります。
- React
- Svelte
- Vue
function App() { const [files, setFiles] = useState<File[]>([]) const [rejected, setRejected] = useState<File[]>([]) return ( <div> <FileInput.Root className={fileInputTheme.root} accept="audio/*" multiple onChange={(files) => { setRejected([]) setFiles(files) }} onReject={(files) => setRejected(files)} > <FileInput.Trigger className={fileInputTheme.trigger}> Choose audio </FileInput.Trigger> <span>{files.length > 0 ? `${files.length} selected` : 'No file'}</span> </FileInput.Root> <ul> {files.map((file) => ( <li key={file.name}> {file.name} ({file.type || 'unknown type'}) </li> ))} </ul> {rejected.length > 0 && ( <p>Not audio: {rejected.map((file) => file.name).join(', ')}</p> )} </div> ) }
<script lang="ts">
import { FileInput } from '@tremolo-ui/svelte'
// Copy this file from the Styling page into your own project.
import fileInputTheme from './FileInput.module.css'
let files: File[] = $state([])
let rejected: File[] = $state([])
</script>
<FileInput.Root
class={fileInputTheme.root}
accept="audio/*"
multiple
onChange={(picked) => {
rejected = []
files = picked
}}
onReject={(picked) => (rejected = picked)}
>
<FileInput.Trigger class={fileInputTheme.trigger}
>Choose audio</FileInput.Trigger
>
<span>{files.length > 0 ? `${files.length} selected` : 'No file'}</span>
</FileInput.Root>
<ul>
{#each files as file}
<li>{file.name} ({file.type || 'unknown type'})</li>
{/each}
</ul>
{#if rejected.length > 0}
<p>Not audio: {rejected.map((file) => file.name).join(', ')}</p>
{/if}
<script setup lang="ts">
import { ref } from 'vue'
import { FileInput, FileInputTrigger } from '@tremolo-ui/vue'
// Copy this file from the Styling page into your own project.
import fileInputTheme from './FileInput.module.css'
const files = ref<File[]>([])
const rejected = ref<File[]>([])
function onChange(picked: File[]) {
rejected.value = []
files.value = picked
}
</script>
<template>
<FileInput
:class="fileInputTheme.root"
accept="audio/*"
multiple
@change="onChange"
@reject="(picked) => (rejected = picked)"
>
<FileInputTrigger :class="fileInputTheme.trigger">
Choose audio
</FileInputTrigger>
<span>{{ files.length > 0 ? `${files.length} selected` : 'No file' }}</span>
</FileInput>
<ul>
<li v-for="(file, i) in files" :key="i">
{{ file.name }} ({{ file.type || 'unknown type' }})
</li>
</ul>
<p v-if="rejected.length > 0">
Not audio: {{ rejected.map((file) => file.name).join(', ') }}
</p>
</template>
インポート
- React
- Svelte
- Vue
import { FileInput } from '@tremolo-ui/react'
import { FileInput } from '@tremolo-ui/svelte'
import { FileInput, FileInputTrigger } from '@tremolo-ui/vue'
このコンポーネントが引き受けること
accept は受け取るときにもう一度照合します。 ブラウザはこの属性をピッカーへのヒントとして扱うので、「すべてのファイル」に切り替えれば何でも選べます。一致しなかったものは onChange ではなく onReject に届くので、黙って何も起きない代わりに理由を表示できます。
同じファイルを 2 回選べます。 ファイル入力は選択が変わらないと change イベントを発火しないので、直前に選んだファイルをもう一度選んでも何も起きないはずでした。読み取った時点で value を空にしています。
コントロールは今もネイティブの input です。 ツリーの中に、見えないけれどタブ順には残る形で置いてあります。フォーカスを取り、Enter でピッカーを開き、アクセシブルな名前を持つのはこの要素です。FileInput.Trigger はその <label> なので、独自の JavaScript 無しにクリックがピッカーへ届きます。
フォーカスが当たるのは見えない要素なので、フォーカスリングは親から描いてください。デモのテーマは .root の :focus-within でそうしています。
input の ARIA 属性は、Root が描くラッパーに残さず Root が受け取ってコントロールへ渡します。「WAV / AIFF、10 MB まで」のような補足は aria-describedby で指し、FileInput.Trigger を使わず名前を取れない場合は aria-label で付けられます。
ドロップも受け取る
FileInput が答えるのはクリックです。ページにドロップされたファイルを受け取るには DropZone を見てください。同じ File[] を報告します。
API リファレンス
各パートには、そのパート固有の props があります。描画する要素の属性(className や style など)も受け取ります。
Svelte / Vue でも props は同じで、書き方だけがそれぞれの流儀になります(className ではなく class、bind:value や v-model、中身は snippet やスロットなど)。Svelte と Vue を参照してください。
状態は data 属性として要素に付くので、セレクタひとつで届きます(スタイリング)。属性は、その状態が on のときだけ存在します。
Root
設定と、隠された <input type="file"> を持ち、選ばれたものを報告します。
| Prop | 型 | 既定値 |
|---|---|---|
accept | string | — |
multiple | boolean | false |
disabled | boolean | false |
onChange | (files: File[]) => void | — |
onReject | (files: File[]) => void | — |
children* | ReactNode | — |
すべての説明: FileInputProps
| Data attribute | Values |
|---|---|
[data-disabled] | disabled が設定されているときに存在します |
Trigger
ピッカーを開き、スクリーンリーダー向けに input へ名前を付けます。<label> として描画されます。
| Prop | 型 | 既定値 |
|---|---|---|
children* | ReactNode | — |
すべての説明: FileInputTriggerProps
| Data attribute | Values |
|---|---|
[data-disabled] | Root に disabled が設定されているときに存在します |