File Upload
Controlled file selection with validation, progress rows, and retry hooks.
File Upload is a standalone package component plus the KuiUploadFile type for controlled state.
import { KuiFileUpload, type KuiUploadFile } from '@kikita-labs/ui';Bind the files model and drive upload transport from your own service.
<div class="basic-file-upload-example">
<kui-file-upload
acceptLabel="PNG, JPG, or PDF up to 10 MB"
[accept]="['image/png', 'image/jpeg', 'application/pdf']"
[maxSize]="10 * 1024 * 1024"
[maxCount]="3"
[(files)]="files"
(retry)="handleRetry($event)"
/>
</div>The component validates picks, but never uploads bytes by itself.
- Picked files enter the model as pending, or error when client validation fails.
- Consumers update each entry to uploading, success, or error as their transport runs.
- The retry output only reports intent; restart the upload and write new state yourself.
- Use compact variant for dense forms and dropzone when drag-and-drop is useful.
- Files rejected by client validation carry
errorKind(typeorsize), so their error text follows the active messages; staticmaxSizeandmaxCountvalues are coerced and an invalid or non-positive value omits the limit.
Set defaults.fileUpload once for the application or for a subtree. Each option resolves as local input > defaults.fileUpload.<option> > built-in default.
import { provideKikitaUi } from '@kikita-labs/ui';
export const appConfig: ApplicationConfig = {
providers: [
provideKikitaUi({
defaults: {
fileUpload: {
/* options below */
},
},
}),
],
};| Name | Type | Default | Description |
|---|---|---|---|
| size | 'xs' | 'sm' | 'md' | 'lg' | — | Component size. Takes precedence over the global defaults.size. |
| variant | 'dropzone' | 'compact' | — | Default variant. |
| mode | 'single' | 'multiple' | — | Default mode. |
| removeIcon | KuiIconGlyph | — | Icon of the remove button. Takes precedence over defaults.icons.remove. See Structural Icons. |
Set any of these on the component or an ancestor to restyle one part. Each token is optional: when it is not set, the part uses the role or scale token in the default column.
| Name | Type | Default | Description |
|---|---|---|---|
| --kui-file-upload-dropzone-bg-hover | CSS custom property | --kui-color-surface | Dropzone background, hover |
| --kui-file-upload-dropzone-focus-ring-color | CSS custom property | --kui-color-focus | Dropzone focus ring color |
| --kui-file-upload-dropzone-border-over | CSS custom property | --kui-color-primary-indicator | Dropzone border color, over |
| --kui-file-upload-dropzone-bg-over | CSS custom property | --kui-color-primary-soft-bg | Dropzone background, over |
| --kui-file-upload-dropzone-border-invalid | CSS custom property | --kui-color-danger-indicator | Dropzone border color, invalid |
| --kui-file-upload-dropzone-bg-invalid | CSS custom property | --kui-color-danger-soft-bg | Dropzone background, invalid |
| --kui-file-upload-dropzone-icon-color | CSS custom property | --kui-color-text-secondary | Dropzone icon color |
| --kui-file-upload-dropzone-icon-color-over | CSS custom property | --kui-color-primary-text | Dropzone icon color, over |
| --kui-file-upload-dropzone-icon-color-invalid | CSS custom property | --kui-color-danger-text | Dropzone icon color, invalid |
| --kui-file-upload-dropzone-text-color | CSS custom property | --kui-color-text | Dropzone text color |
| --kui-file-upload-dropzone-text-emphasis-color | CSS custom property | --kui-color-primary-soft-text | Dropzone text emphasis color |
| --kui-file-upload-dropzone-hint-color | CSS custom property | --kui-color-text-secondary | Dropzone hint color |
| --kui-file-upload-compact-hint-color | CSS custom property | --kui-color-text-secondary | Compact hint color |
| --kui-file-upload-form-error-color | CSS custom property | --kui-color-danger-text | Form error color |
| --kui-file-upload-item-border | CSS custom property | --kui-color-border | Item border color |
| --kui-file-upload-item-bg | CSS custom property | --kui-color-surface | Item background |
| --kui-file-upload-item-focus-ring-color | CSS custom property | --kui-color-focus | Item focus ring color |
| --kui-file-upload-item-preview-bg | CSS custom property | --kui-color-surface-elevated | Item preview background |
| --kui-file-upload-item-preview-color | CSS custom property | --kui-color-text-secondary | Item preview color |
| --kui-file-upload-item-preview-bg-pdf | CSS custom property | --kui-color-danger-soft-bg | Item preview background, pdf |
| --kui-file-upload-item-preview-color-pdf | CSS custom property | --kui-color-danger-soft-text | Item preview color, pdf |
| --kui-file-upload-item-preview-bg-doc | CSS custom property | --kui-color-info-soft-bg | Item preview background, doc |
| --kui-file-upload-item-preview-color-doc | CSS custom property | --kui-color-info-soft-text | Item preview color, doc |
| --kui-file-upload-item-preview-bg-zip | CSS custom property | --kui-color-warning-soft-bg | Item preview background, zip |
| --kui-file-upload-item-preview-color-zip | CSS custom property | --kui-color-warning-soft-text | Item preview color, zip |
| --kui-file-upload-item-name-color | CSS custom property | --kui-color-text | Item name color |
| --kui-file-upload-item-meta-color | CSS custom property | --kui-color-text-secondary | Item meta color |
| --kui-file-upload-item-success-color | CSS custom property | --kui-color-success-text | Item success color |
| Name | Type | Default | Description |
|---|---|---|---|
| --kui-file-upload-gap | CSS custom property | --kui-space-4 | Gap |
| --kui-file-upload-dropzone-padding-block | CSS custom property | --kui-space-8 | Dropzone padding, block |
| --kui-file-upload-dropzone-padding-inline | CSS custom property | --kui-space-6 | Dropzone padding, inline |
| --kui-file-upload-dropzone-gap | CSS custom property | --kui-space-2 | Dropzone gap |
| --kui-file-upload-dropzone-padding-has-files | CSS custom property | --kui-space-4 | Dropzone padding, has files |
| --kui-file-upload-dropzone-text-font-size | CSS custom property | --kui-text-sm-size | Dropzone text font size |
| --kui-file-upload-dropzone-hint-font-size | CSS custom property | --kui-text-xs-size | Dropzone hint font size |
| --kui-file-upload-compact-trigger-gap | CSS custom property | --kui-space-3 | Compact trigger gap |
| --kui-file-upload-compact-hint-font-size | CSS custom property | --kui-text-xs-size | Compact hint font size |
| --kui-file-upload-form-error-font-size | CSS custom property | --kui-text-xs-size | Form error font size |
| --kui-file-upload-list-gap | CSS custom property | --kui-space-2 | List gap |
| --kui-file-upload-item-gap | CSS custom property | --kui-space-3 | Item gap |
| --kui-file-upload-item-padding-block | CSS custom property | --kui-space-2 | Item padding, block |
| --kui-file-upload-item-padding-inline | CSS custom property | --kui-space-3 | Item padding, inline |
| --kui-file-upload-item-radius | CSS custom property | --kui-radius-md | Item corner radius |
| --kui-file-upload-item-preview-radius | CSS custom property | --kui-radius-sm | Item preview corner radius |
| --kui-file-upload-item-preview-font-size | CSS custom property | --kui-text-2xs-size | Item preview font size |
| --kui-file-upload-item-name-font-size | CSS custom property | --kui-text-sm-size | Item name font size |
| --kui-file-upload-item-meta-gap | CSS custom property | --kui-space-2 | Item meta gap |
| --kui-file-upload-item-meta-font-size | CSS custom property | --kui-text-xs-size | Item meta font size |
| --kui-file-upload-item-error-gap | CSS custom property | --kui-space-2 | Item error gap |
| --kui-file-upload-dropzone-padding-block-sm | CSS custom property | --kui-space-5 | Dropzone padding, block sm |
| --kui-file-upload-dropzone-padding-inline-sm | CSS custom property | --kui-space-4 | Dropzone padding, inline sm |
| --kui-file-upload-dropzone-gap-sm | CSS custom property | --kui-space-1 | Dropzone gap, sm |
| --kui-file-upload-dropzone-text-font-size-sm | CSS custom property | --kui-text-xs-size | Dropzone text font size, sm |
| --kui-file-upload-item-name-font-size-sm | CSS custom property | --kui-text-xs-size | Item name font size, sm |
| --kui-file-upload-dropzone-padding-block-lg | CSS custom property | --kui-space-12 | Dropzone padding, block lg |
| --kui-file-upload-dropzone-padding-inline-lg | CSS custom property | --kui-space-8 | Dropzone padding, inline lg |
| --kui-file-upload-dropzone-gap-lg | CSS custom property | --kui-space-3 | Dropzone gap, lg |
| --kui-file-upload-dropzone-text-font-size-lg | CSS custom property | --kui-text-md-size | Dropzone text font size, lg |
| --kui-file-upload-item-name-font-size-lg | CSS custom property | --kui-text-md-size | Item name font size, lg |
| --kui-file-upload-dropzone-icon-size | CSS custom property | 32px (24px sm, 40px lg) | Dropzone icon size |
Every text the component owns (accessible names, visible words, announcements) is a typed message with an English default. Override it for the application with provideKikitaUi({ messages }), or for a subtree with provideKuiMessages.
| Name | Type | Default | Description |
|---|---|---|---|
| dropzoneLabel | string | — | Accessible name of the dropzone. Default Upload file. Drag and drop or click to browse. |
| promptBefore | string | — | Text before the emphasised action in the dropzone. Default Drag files here or . |
| promptAction | string | — | Emphasised action in the dropzone. Default choose a file. |
| promptAfter | string | — | Text after the emphasised action in the dropzone. Default empty. |
| chooseFile | string | — | Text of the presentational button in the dropzone. Default Choose file. |
| attachFile | string | — | Text of the compact trigger. Default Attach file. |
| invalidType | string | — | Error for a file whose type is not accepted. Default Invalid file type. |
| tooLarge | KuiMessageFn<{ max: string; }> | — | Error for a file over the size limit. Default Exceeds max size (max {max}). |
| tooMany | KuiMessageFn<{ max: number; }> | — | Error for too many files. Default Maximum {max} file(s), singular and plural. |
| uploading | KuiMessageFn<{ name: string; }> | — | Accessible name of a file's progress bar. Default Uploading {name}. |
| removeFile | KuiMessageFn<{ name: string; }> | — | Accessible name of a file's remove button. Default Remove {name}. |
| done | string | — | Status of a finished upload. Default Done. |
| queued | string | — | Status of a file waiting for upload. Default Queued. |
| retry | string | — | Retry action of a failed upload. Default Retry. |
Inputs verified against @kikita-labs/ui v2.0.0 public typings and package docs.
| Name | Type | Default | Description |
|---|---|---|---|
| variant | 'dropzone' | 'compact' | 'dropzone' | Renders the full drag-and-drop zone or a compact attach button. |
| mode | 'single' | 'multiple' | 'multiple' | Controls whether a new selection replaces or appends to the file list. |
| accept | readonly string[] | undefined | Allowed MIME types. Omit it to accept any file type. |
| acceptLabel | string | undefined | Human-readable format and limit hint shown near the picker. |
| maxSize | number | undefined | Maximum file size in bytes. |
| maxCount | number | undefined | Maximum number of files in multiple mode. |
| size | 'sm' | 'md' | 'lg' | 'md' | Controls row height, thumbnail scale, and trigger density. |
| disabled | boolean | false | Stops drag, click, and keyboard file-picking interactions. |
| [(files)] | readonly KuiUploadFile[] | [] | Controlled file list. Consumers own upload status and progress after picking. |
| (retry) | KuiUploadFile | - | Emits when an errored item retry action is activated. |
| KuiUploadFile.status | 'pending' | 'uploading' | 'success' | 'error' | - | Per-file state written by the component initially and then by the consumer. |
| messages | Partial<KuiFileUploadMessages> | undefined | undefined | Per-instance text overrides: prompt, buttons, statuses and errors. Sizes and percentages are formatted with the locale (2.5 MB, 340 kB). They win over scoped and root messages. |
| KuiUploadFile.errorKind | 'type' | 'size' | - | Set by the component when client-side validation rejects a file; the displayed text then follows the active messages. Omit it for errors you set yourself. |
| KuiFileUploadOptions | interface | - | Shape of defaults.fileUpload: size, variant, mode and removeIcon (takes precedence over defaults.icons.remove). |
Drag-and-drop is optional; keyboard users still activate a native file input.
- Keep the visible acceptLabel specific so the dropzone aria-label is meaningful.
- Use Enter or Space on the dropzone or the compact
Attach filebutton to open the native picker. The native file input isaria-hiddenand out of the tab order: the dropzone or the compact button is the control. - The small
Choose filelabel inside the dropzone is presentational (aria-hidden), not a second button, so a click on it reaches the dropzone and no interactive control is nested inside another. - Tab reaches file rows and actions; Delete or Backspace removes a focused file item.
- File Upload is not a Signal Forms control; compose required state around the files model.
Consumer-visible changes of @kikita-labs/ui 2.0 for File Upload.
- The class is
KuiFileUpload(it wasKuiFileUploadComponent);ng update @kikita-labs/uirenames the import. - Size, variant and mode fall back to
defaults.fileUpload; static numericmaxSizeandmaxCountattributes are coerced. Sizes useIntlunits (kB, it wasKB), and the too-many-files error readsMaximum 1 filefor one. - The native input and the small label inside the dropzone are
aria-hidden, so the dropzone is the only interactive element and the axe nested-interactive violation is gone. - Rejected files carry the new
errorKindfield so their message follows the active messages.