File Input

An input component for selecting and uploading files

Unified Component (Mode-Based)

A single component with different modes for various use cases

Drag & Drop Mode

Drop images or PDFs here

Max 10MB per file

Regular Input Mode

Button-Only Mode


Code Svelte
1
2<script lang="ts">
3	import { FileInput } from "@kareyes/aether";
4
5	let dragDropFiles: FileList | null = $state(null);
6	let regularFiles: FileList | null = $state(null);
7	let buttonFiles: FileList | null = $state(null);
8
9	function handleFilesChange(name: string) {
10		return (files: FileList | null) => {
11			console.log(`${name} files changed:`, files ? Array.from(files).map(f => f.name) : 'No files');
12			};
13		}
14
15	function handleError(name: string) {
16		return (error: string) => {
17			console.error(`${name} error:`, error);
18		};
19	}
20</script>
21
22<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
23	<div class="space-y-2">
24		<h3 class="text-sm font-medium">Drag & Drop Mode</h3>
25		<FileInput
26			mode="drag-drop"
27			validation={{
28				maxSize: 10 * 1024 * 1024,
29				acceptedTypes: ['image/*', '.pdf']
30			}}
31			onFilesChange={(files) => {
32				dragDropFiles = files;
33				handleFilesChange('Drag & Drop')(files);
34			}}
35			onError={handleError('Drag & Drop')}
36			dragDropProps={{
37				label: "Drop images or PDFs here",
38				description: "Max 10MB per file",
39				showFileList: true
40			}}
41		/>
42	</div>
43
44	<div class="space-y-2">
45		<h3 class="text-sm font-medium">Regular Input Mode</h3>
46		<FileInput
47			mode="regular"
48			validation={{
49				maxFiles: 3,
50				acceptedTypes: ['.doc', '.docx', '.txt']
51			}}
52			onFilesChange={(files) => {
53				regularFiles = files;
54				handleFilesChange('Regular')(files);
55			}}
56			onError={handleError('Regular')}
57			regularProps={{
58				placeholder: "Select up to 3 files...",
59				showFileCount: true
60			}}
61		/>
62	</div>
63
64	<div class="space-y-2">
65		<h3 class="text-sm font-medium">Button-Only Mode</h3>
66		<FileInput
67			mode="button-only"
68			validation={{
69				maxFiles: 1,
70				maxSize: 5 * 1024 * 1024,
71				acceptedTypes: ['image/*']
72			}}
73			onFilesChange={(files) => {
74				buttonFiles = files;
75				handleFilesChange('Button')(files);
76			}}
77			onError={handleError('Button')}
78			buttonProps={{
79				buttonText: "Upload Avatar",
80				variant: "filled",
81				size: "lg",
82				showCount: true
83			}}
84		/>
85	</div>
86</div>
87

Dedicated Components

Each component optimized for specific use cases with sleek UI

FileInputDragDrop

Best for large file uploads with visual feedback

Drop media files here

Images and videos only

FileInputRegular (Sleek UI)

Input-group based design with clear/browse actions

FileInputButton

Minimal footprint for inline forms


Code Svelte
1
2<script lang="ts">
3	import { FileInputDragDrop, FileInputRegular, FileInputButton } from "@kareyes/aether";
4
5	function handleFilesChange(name: string) {
6		return (files: FileList | null) => {
7			console.log(`${name} files changed:`, files ? Array.from(files).map(f => f.name) : 'No files');
8			};
9		}
10
11	function handleError(name: string) {
12		return (error: string) => {
13			console.error(`${name} error:`, error);
14		};
15	}
16</script>
17
18<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
19	<div class="space-y-2">
20		<h3 class="text-sm font-medium">FileInputDragDrop</h3>
21		<p class="text-xs text-muted-foreground">Best for large file uploads with visual feedback</p>
22		<FileInputDragDrop
23			validation={{
24				maxSize: 10 * 1024 * 1024,
25				acceptedTypes: ['image/*', 'video/*']
26			}}
27			onFilesChange={handleFilesChange('Direct Drag Drop')}
28			onError={handleError('Direct Drag Drop')}
29			label="Drop media files here"
30			description="Images and videos only"
31			multiple={true}
32		/>
33	</div>
34
35	<div class="space-y-2">
36		<h3 class="text-sm font-medium">FileInputRegular (Sleek UI)</h3>
37		<p class="text-xs text-muted-foreground">Input-group based design with clear/browse actions</p>
38		<FileInputRegular
39			validation={{
40				maxFiles: 5,
41				acceptedTypes: ['.csv', '.xlsx', '.json']
42			}}
43			onFilesChange={handleFilesChange('Direct Regular')}
44			onError={handleError('Direct Regular')}
45			placeholder="Choose spreadsheets..."
46			showFileCount={true}
47			multiple={true}
48		/>
49	</div>
50
51	<div class="space-y-2">
52		<h3 class="text-sm font-medium">FileInputButton</h3>
53		<p class="text-xs text-muted-foreground">Minimal footprint for inline forms</p>
54		<FileInputButton
55			validation={{
56				maxFiles: 1,
57				maxSize: 2 * 1024 * 1024,
58				acceptedTypes: ['.png', '.jpg', '.jpeg', '.gif']
59			}}
60			onFilesChange={handleFilesChange('Direct Button')}
61			onError={handleError('Direct Button')}
62			buttonText="Choose Image"
63			variant="ghost"
64			showCount={false}
65			showFileList={true}
66		/>
67	</div>
68</div>

Regular Input - Sleek UI Showcase

Enhanced with input-group component for a modern, polished experience

Single File Upload

Multiple Files with Count

Without File List

Required Field


Code Svelte
1
2<script lang="ts">
3	import { FileInputRegular } from "@kareyes/aether";
4
5
6	function handleFilesChange(name: string) {
7		return (files: FileList | null) => {
8			console.log(`${name} files changed:`, files ? Array.from(files).map(f => f.name) : 'No files');
9			};
10		}
11
12	function handleError(name: string) {
13		return (error: string) => {
14			console.error(`${name} error:`, error);
15		};
16	}
17</script>
18
19<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
20	<div class="space-y-2">
21		<h3 class="text-sm font-medium">Single File Upload</h3>
22		<FileInputRegular
23			validation={{
24				maxFiles: 1,
25				maxSize: 5 * 1024 * 1024,
26				acceptedTypes: ['image/*', '.pdf']
27			}}
28			onFilesChange={handleFilesChange('Single File')}
29			onError={handleError('Single File')}
30			placeholder="Select an image or PDF..."
31			showFileCount={false}
32			showFileList={true}
33			multiple={false}
34		/>
35	</div>
36
37	<div class="space-y-2">
38		<h3 class="text-sm font-medium">Multiple Files with Count</h3>
39		<FileInputRegular
40			validation={{
41				maxFiles: 10,
42				acceptedTypes: ['.jpg', '.png', '.gif', '.webp']
43			}}
44			onFilesChange={handleFilesChange('Multiple Images')}
45			onError={handleError('Multiple Images')}
46			placeholder="Select up to 10 images..."
47			showFileCount={true}
48			showFileList={true}
49			multiple={true}
50		/>
51	</div>
52
53	<div class="space-y-2">
54		<h3 class="text-sm font-medium">Without File List</h3>
55		<FileInputRegular
56			validation={{
57				acceptedTypes: ['.doc', '.docx', '.txt']
58			}}
59			onFilesChange={handleFilesChange('Documents')}
60			onError={handleError('Documents')}
61			placeholder="Choose document files..."
62			showFileCount={true}
63			showFileList={false}
64			multiple={true}
65		/>
66	</div>
67
68	<div class="space-y-2">
69		<h3 class="text-sm font-medium">Required Field</h3>
70		<FileInputRegular
71			validation={{
72				maxFiles: 1,
73				acceptedTypes: ['.pdf']
74			}}
75			onFilesChange={handleFilesChange('Resume')}
76			onError={handleError('Resume')}
77			placeholder="Upload your resume (PDF only)..."
78			showFileCount={false}
79			showFileList={true}
80			multiple={false}
81			required={true}
82		/>
83	</div>
84</div>

Style Variants

Different button styles for the file input trigger

Default Variant

Filled Variant

Ghost Variant


Code Svelte
1
2<script lang="ts">
3	import { FileInput } from "@kareyes/aether";
4</script>
5
6<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
7	<FileInput mode="button-only" buttonProps={{ buttonText: "Default Button", variant: "default", size: "default" }} />
8	<FileInput mode="button-only" buttonProps={{ buttonText: "Filled Button", variant: "filled", size: "default" }} />
9	<FileInput mode="button-only" buttonProps={{ buttonText: "Ghost Button", variant: "ghost", size: "default" }} />
10</div>

Size Options

Available button sizes for the file input

Small

Default

Large


Code Svelte
1
2<script lang="ts">
3	import { FileInput } from "@kareyes/aether";
4</script>
5
6<div class="flex flex-wrap gap-4 items-end">
7	<FileInput mode="button-only" buttonProps={{ buttonText: "Small", size: "sm" }} />
8	<FileInput mode="button-only" buttonProps={{ buttonText: "Default", size: "default" }} />
9	<FileInput mode="button-only" buttonProps={{ buttonText: "Large", size: "lg" }} />
10</div>

Error State

Pass an error prop to show a validation message below the input. Errors can be set statically or driven reactively via onError.

Regular — validation error

Drag & Drop — static error

Drop image here

or click to select files

Button — static error


Code Svelte
1
2<script lang="ts">
3	import { FileInputRegular, FileInputDragDrop, FileInputButton } from "@kareyes/aether";
4
5	let regularError = $state("");
6</script>
7
8<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
9	<!-- Regular — error triggered by validation failure -->
10	<div class="space-y-2">
11		<h3 class="text-sm font-medium">Regular — validation error</h3>
12		<FileInputRegular
13			validation={{ maxSize: 1, acceptedTypes: [".pdf"] }}
14			onError={(err) => (regularError = err)}
15			onFilesChange={() => (regularError = "")}
16			placeholder="Upload a PDF..."
17			error={!!regularError}
18		/>
19	</div>
20
21	<!-- Drag & Drop — static error prop -->
22	<div class="space-y-2">
23		<h3 class="text-sm font-medium">Drag & Drop — static error</h3>
24		<FileInputDragDrop
25			validation={{ maxSize: 5 * 1024 * 1024, acceptedTypes: ["image/*"] }}
26			error
27			label="Drop image here"
28		/>
29	</div>
30
31	<!-- Button — static error prop -->
32	<div class="space-y-2">
33		<h3 class="text-sm font-medium">Button — static error</h3>
34		<FileInputButton
35			validation={{ maxFiles: 1 }}
36			error
37			buttonText="Choose File"
38		/>
39	</div>
40</div>

Wrapped in Field

Nest any file input inside <Field> to get a label, description, required indicator, and error message for free — all properly associated with the control.

PDF or Word doc, max 5 MB.

JPEG or PNG, max 2 MB.

Drop your photo here

JPEG or PNG only

Any file type, max 10 MB.

Uploads are disabled for read-only profiles.


Code Svelte
1
2<script lang="ts">
3	import { FileInputRegular, FileInputDragDrop, FileInputButton, Field } from "@kareyes/aether";
4
5	let resumeError = $state("");
6</script>
7
8<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
9	<!-- Regular inside Field — label, description, required, and error -->
10	<Field label="Résumé" description="PDF or Word doc, max 5 MB." required error={resumeError}>
11		<FileInputRegular
12			validation={{ maxFiles: 1, maxSize: 5 * 1024 * 1024, acceptedTypes: [".pdf", ".doc", ".docx"] }}
13			onError={(err) => (resumeError = err)}
14			onFilesChange={() => (resumeError = "")}
15			placeholder="Select your résumé…"
16		/>
17	</Field>
18
19	<!-- Drag-drop inside Field -->
20	<Field label="Cover Photo" description="JPEG or PNG, max 2 MB.">
21		<FileInputDragDrop
22			validation={{ maxFiles: 1, maxSize: 2 * 1024 * 1024, acceptedTypes: ["image/jpeg", "image/png"] }}
23			label="Drop your photo here"
24			description="JPEG or PNG only"
25		/>
26	</Field>
27
28	<!-- Button inside Field -->
29	<Field label="Attachment" description="Any file type, max 10 MB.">
30		<FileInputButton
31			validation={{ maxFiles: 1, maxSize: 10 * 1024 * 1024 }}
32			buttonText="Attach File"
33			showFileList
34		/>
35	</Field>
36
37	<!-- Disabled via Field prop -->
38	<Field label="Locked Upload" description="Uploads are disabled for read-only profiles." disabled>
39		<FileInputRegular disabled placeholder="Uploads disabled" />
40	</Field>
41</div>

File Status

Current file selection state from the examples above

Drag & Drop Files

No files selected

Regular Input Files

No files selected

Button Files

No files selected