0 Files:
<MudFileUpload T="IBrowserFile" FilesChanged="UploadFiles"> <ActivatorContent> <MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.CloudUpload"> Upload Files </MudButton> </ActivatorContent> </MudFileUpload> <MudFileUpload T="IBrowserFile" FilesChanged="UploadFiles"> <ActivatorContent> <MudFab Color="Color.Secondary" StartIcon="@Icons.Material.Filled.Image" Label="Load picture" /> </ActivatorContent> </MudFileUpload> <MudFileUpload T="IBrowserFile" FilesChanged="UploadFiles"> <ActivatorContent> <MudFab Color="Color.Success" StartIcon="@Icons.Material.Filled.AttachFile" /> </ActivatorContent> </MudFileUpload> <MudFileUpload T="IBrowserFile" FilesChanged="UploadFiles"> <ActivatorContent> <MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.PhotoCamera"> </MudIconButton> </ActivatorContent> </MudFileUpload> <MudFileUpload T="IBrowserFile" FilesChanged="UploadFiles" Disabled> <ActivatorContent> <MudButton Variant="Variant.Filled" Color="Color.Primary"> Disabled Button </MudButton> </ActivatorContent> </MudFileUpload> @if (_files != null) { <MudText Typo="@Typo.h6">@_files.Count() File@(_files.Count() == 1 ? "" : "s"):</MudText> <MudList T="string"> @foreach (var file in _files) { <MudListItem Icon="@Icons.Material.Filled.AttachFile" @key=""> @file.Name <code>@file.Size bytes</code> </MudListItem> } </MudList> }
@code { IList<IBrowserFile> _files = new List<IBrowserFile>(); private void UploadFiles(IBrowserFile file) { _files.Add(file); //TODO upload the files to the server } }
Multiple and Accept
Allow multiple files with T="IReadOnlyList<IBrowserFile>"
or limit the valid file types with Accept
.
To upload more than 10 files, you must specify a MaximumFileCount
.
<MudFileUpload T="IReadOnlyList<IBrowserFile>" FilesChanged="UploadFiles"> <ActivatorContent> <MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.CloudUpload"> Multiple Files </MudButton> </ActivatorContent> </MudFileUpload> <MudFileUpload T="IBrowserFile" Accept=".pdf" FilesChanged="UploadFiles2" MaximumFileCount="100"> <ActivatorContent> <MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.CloudUpload"> Only .pdf files </MudButton> </ActivatorContent> </MudFileUpload> <MudFileUpload T="IBrowserFile" Accept=".png, .jpg" FilesChanged="UploadFiles2" MaximumFileCount="100"> <ActivatorContent> <MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.CloudUpload"> Only image files </MudButton> </ActivatorContent> </MudFileUpload> @if (files != null) { <MudList T="string"> @foreach (var file in files) { <MudListItem Icon="@Icons.Material.Filled.AttachFile"> @file.Name <code>@file.Size bytes</code> </MudListItem> } </MudList> }
@code { IList<IBrowserFile> files = new List<IBrowserFile>(); private void UploadFiles(IReadOnlyList<IBrowserFile> files) { foreach (var file in files) { this.files.Add(file); } //TODO upload the files to the server } private void UploadFiles2(IBrowserFile file) { files.Add(file); //TODO upload the files to the server } }
Form Validation
Use the For
property to validate your files within a form, and bind your files to your model class using @bind-Files
.
You can then handle the file upload logic within your MudForm
submit method.
The component provides a public ClearAsync
method that you can use as OnClick
handler for a button to clear files and update the form state.
@using FluentValidation @using Severity = MudBlazor.Severity @inject ISnackbar Snackbar <MudCard> <MudForm Model="" @ref="" Validation="@(ValidationRules.ValidateValue)" ValidationDelay="0"> <MudCardContent> <MudStack> <MudTextField @bind-Value="model.Name" For="@(() => model.Name)" Immediate="true" Label="Name" /> <MudGrid Justify="@Justify.FlexEnd" Spacing="1"> <MudItem> <MudFileUpload @ref="@_fileUpload" T="IBrowserFile" For="@(() => model.File)" @bind-Files="model.File" OnFilesChanged="UploadFiles" SuppressOnChangeWhenInvalid="SuppressOnChangeWhenInvalid"> <ActivatorContent> <MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.CloudUpload"> Upload Files </MudButton> </ActivatorContent> </MudFileUpload> </MudItem> <MudItem> <MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Clear" OnClick=""> Clear Files </MudButton> </MudItem> </MudGrid> </MudStack> </MudCardContent> <MudCardActions> <MudSwitch Color="Color.Primary" @bind-Value="SuppressOnChangeWhenInvalid">Suppress OnChange When Invalid</MudSwitch> <MudButton Variant="Variant.Filled" Color="Color.Primary" Class="ml-auto" OnClick="@(async () => await Submit())">Submit</MudButton> </MudCardActions> </MudForm> </MudCard>
@code { private MudForm form; private FileModel model = new(); private FileModelFluentValidator ValidationRules = new(); private bool SuppressOnChangeWhenInvalid; private MudFileUpload<IBrowserFile> _fileUpload; private void UploadFiles(InputFileChangeEventArgs e) { //If SuppressOnChangeWhenInvalid is false, perform your validations here Snackbar.Configuration.PositionClass = Defaults.Classes.Position.TopCenter; Snackbar.Add($"This file has the extension {model.File.Name.Split(".").Last()}", Severity.Info); //TODO upload the files to the server } private async Task Submit() { await form.Validate(); if (form.IsValid) { Snackbar.Add("Submitted!"); } } private Task ClearAsync() => _fileUpload?.ClearAsync() ?? Task.CompletedTask; public class FileModel { public string Name { get; set; } public IBrowserFile File { get; set; } } /// <summary> /// A standard AbstractValidator which contains multiple rules and can be shared with the back end API /// </summary> /// <typeparam name="OrderModel"></typeparam> public class FileModelFluentValidator : AbstractValidator<FileModel> { public FileModelFluentValidator() { RuleFor(x => x.Name) .NotEmpty() .Length(1, 100); RuleFor(x => x.File) .NotEmpty(); When(x => x.File != null, () => { RuleFor(x => x.File.Size).LessThanOrEqualTo(10485760).WithMessage("The maximum file size is 10 MB"); }); } public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) => { var result = await ValidateAsync(ValidationContext<FileModel>.CreateWithOptions((FileModel)model, x => x.IncludeProperties(propertyName))); if (result.IsValid) return Array.Empty<string>(); return result.Errors.Select(e => e.ErrorMessage); }; } }
Event Options
You can use either Files
and FilesChanged
or the OnFilesChanged
callback.
The former is better when used within a MudForm
, and the latter is better for custom scenarios.
When using OnFilesChanged
, it will fire regardless of validation by default, but can be configured to only fire when valid using SuppressOnChangeWhenInvalid
.
0 Files:
<MudFileUpload T="IBrowserFile" FilesChanged="UploadFiles"> <ActivatorContent> <MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.CloudUpload"> Upload using FileValueChanged </MudButton> </ActivatorContent> </MudFileUpload> <MudFileUpload T="IBrowserFile" OnFilesChanged="UploadFiles"> <ActivatorContent> <MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.CloudUpload"> Upload using OnFilesChanged </MudButton> </ActivatorContent> </MudFileUpload> @if (files != null) { <MudText Typo="@Typo.h6">@files.Count() File@(files.Count() == 1 ? "" : "s"):</MudText> <MudList T="string"> @foreach (var file in files) { <MudListItem Icon="@Icons.Material.Filled.AttachFile" @key=""> @file.Name <code>@file.Size bytes</code> </MudListItem> } </MudList> }
@code { IList<IBrowserFile> files = new List<IBrowserFile>(); private void UploadFiles(IBrowserFile file) { files.Add(file); //TODO upload the files to the server } private void UploadFiles(InputFileChangeEventArgs args) { files.Add(args.File); //TODO upload the files to the server } }
SelectedTemplate
You can use the SelectedTemplate
RenderFragment to display the current files.
Its @context
parameter matches T
.
No File
No Files
<MudFileUpload T="IBrowserFile"> <ActivatorContent> <MudButton Variant="Variant.Filled" Color="Color.Primary"> Single File </MudButton> </ActivatorContent> <SelectedTemplate> @if (context != null) { <MudText>@context.Name</MudText> } else { <MudText>No File</MudText> } </SelectedTemplate> </MudFileUpload> <MudFileUpload T="IReadOnlyList<IBrowserFile>" multiple> <ActivatorContent> <MudButton Variant="Variant.Filled" Color="Color.Secondary"> Multiple Files </MudButton> </ActivatorContent> <SelectedTemplate> @if (context != null) { @foreach (var file in context) { <MudText>@file.Name</MudText> } } else { <MudText>No Files</MudText> } </SelectedTemplate> </MudFileUpload>
Append Multiple Files
With AppendMultipleFiles
set to true, when additional files are selected they will be appended to the existing list.
No Files
No Files
<MudFileUpload T="IReadOnlyList<IBrowserFile>" AppendMultipleFiles> <ActivatorContent> <MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.CloudUpload"> AppendMultipleFiles = true </MudButton> </ActivatorContent> <SelectedTemplate> @if (context != null) { @foreach (var file in context) { <MudText>@file.Name</MudText> } } else { <MudText>No Files</MudText> } </SelectedTemplate> </MudFileUpload> <MudFileUpload T="IReadOnlyList<IBrowserFile>" AppendMultipleFiles="false"> <ActivatorContent> <MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.CloudUpload"> AppendMultipleFiles = false </MudButton> </ActivatorContent> <SelectedTemplate> @if (context != null) { @foreach (var file in context) { <MudText>@file.Name</MudText> } } else { <MudText>No Files</MudText> } </SelectedTemplate> </MudFileUpload>
Drag and Drop Example
Using the examples below, you can compose a drag-and-drop uploader.
Custom Scenario
Drag and drop files here or click
@inject ISnackbar Snackbar <MudStack Style="width: 100%"> <MudFileUpload T="IReadOnlyList<IBrowserFile>" @ref="@_fileUpload" OnFilesChanged="OnInputFileChanged" AppendMultipleFiles Hidden="" InputClass="absolute mud-width-full mud-height-full overflow-hidden z-10" InputStyle="opacity:0" tabindex="-1" @ondrop="" @ondragenter="" @ondragleave="" @ondragend=""> <ActivatorContent> <MudPaper Height="300px" Outlined="true" Class="@_dragClass"> <MudText Typo="Typo.h6"> Drag and drop files here or click </MudText> @foreach (var file in _fileNames) { <MudChip T="string" Color="Color.Dark" Text="" tabindex="-1" /> } </MudPaper> </ActivatorContent> </MudFileUpload> <MudToolBar Gutters="" Class="relative d-flex justify-end gap-4"> <MudButton Color="Color.Primary" OnClick="" Variant="Variant.Filled"> Open file picker </MudButton> <MudButton Color="Color.Primary" Disabled="@(!_fileNames.Any())" OnClick="" Variant="Variant.Filled"> Upload </MudButton> <MudButton Color="Color.Error" Disabled="@(!_fileNames.Any())" OnClick="" Variant="Variant.Filled"> Clear </MudButton> </MudToolBar> </MudStack>
@code { #nullable enable private const string DefaultDragClass = "relative rounded-lg border-2 border-dashed pa-4 mt-4 mud-width-full mud-height-full"; private string _dragClass = DefaultDragClass; private readonly List<string> _fileNames = new(); private MudFileUpload<IReadOnlyList<IBrowserFile>>? _fileUpload; private async Task ClearAsync() { await (_fileUpload?.ClearAsync() ?? Task.CompletedTask); _fileNames.Clear(); ClearDragClass(); } private Task OpenFilePickerAsync() => _fileUpload?.OpenFilePickerAsync() ?? Task.CompletedTask; private void OnInputFileChanged(InputFileChangeEventArgs e) { ClearDragClass(); var files = e.GetMultipleFiles(); foreach (var file in files) { _fileNames.Add(file.Name); } } private void Upload() { // Upload the files here Snackbar.Configuration.PositionClass = Defaults.Classes.Position.TopCenter; Snackbar.Add("TODO: Upload your files!"); } private void SetDragClass() => _dragClass = $"{DefaultDragClass} mud-border-primary"; private void ClearDragClass() => _dragClass = DefaultDragClass; }
With Form Validation
@using FluentValidation @inject ISnackbar Snackbar <MudStack Style="width: 100%"> <MudForm Model="@_model" @bind-IsValid="_isValid" @bind-IsTouched="_isTouched" Validation="@_validationRules.ValidateValue"> <MudItem xs="12"> <MudFileUpload T="IReadOnlyList<IBrowserFile>" @ref="@_fileUpload" @bind-Files="_model.Files" For="@(() => _model.Files)" AppendMultipleFiles Hidden="" InputClass="absolute mud-width-full mud-height-full overflow-hidden z-10" InputStyle="opacity:0" ErrorText="@string.Empty" tabindex="-1" @ondrop="" @ondragenter="" @ondragleave="" @ondragend=""> <ActivatorContent> <MudPaper Height="300px" Outlined="true" Class="@_dragClass"> <MudText Typo="Typo.h6"> Drag and drop files here or click </MudText> @foreach (var file in _model.Files?.Select(file => file.Name) ?? Enumerable.Empty<string>()) { <MudChip T="string" Color="Color.Dark" Text="" /> } </MudPaper> </ActivatorContent> </MudFileUpload> <MudToolBar Gutters="" Class="relative d-flex justify-end gap-4"> <MudButton Color="Color.Primary" OnClick="" Variant="Variant.Filled"> Open file picker </MudButton> <MudButton Color="Color.Primary" Disabled="@(!_isValid || !_isTouched || _model.Files is null || !_model.Files.Any())" OnClick="" Variant="Variant.Filled"> Upload </MudButton> <MudButton Color="Color.Error" Disabled="@(_model.Files is null || !_model.Files.Any())" OnClick="" Variant="Variant.Filled"> Clear </MudButton> </MudToolBar> </MudItem> <MudItem> @if (_fileUpload?.ValidationErrors.Any() ?? false) { <MudText Color="Color.Error" Typo="@Typo.caption"> @_fileUpload?.ValidationErrors[0] </MudText> } </MudItem> <MudItem xs="12"> IsValid: @_isValid - IsTouched: @_isTouched </MudItem> </MudForm> </MudStack>
@code { #nullable enable public class Model { public IReadOnlyList<IBrowserFile>? Files { get; set; } = new List<IBrowserFile>(); } private Model _model = new(); private ModelFluentValidator _validationRules = new(); private MudFileUpload<IReadOnlyList<IBrowserFile>>? _fileUpload; private bool _isValid; private bool _isTouched; private const string FileContent = "this is content"; private const string DefaultDragClass = "relative rounded-lg border-2 border-dashed pa-4 mt-4 mud-width-full mud-height-full"; private string _dragClass = DefaultDragClass; private void Upload() { // Upload the files here Snackbar.Configuration.PositionClass = Defaults.Classes.Position.TopCenter; Snackbar.Add("TODO: Upload your files!"); } private void SetDragClass() => _dragClass = $"{DefaultDragClass} mud-border-primary"; private void ClearDragClass() => _dragClass = DefaultDragClass; private Task OpenFilePickerAsync() => _fileUpload?.OpenFilePickerAsync() ?? Task.CompletedTask; private Task ClearAsync() => _fileUpload?.ClearAsync() ?? Task.CompletedTask; public class ModelFluentValidator : AbstractValidator<Model> { public ModelFluentValidator() { RuleFor(x => x.Files) .NotEmpty() .WithMessage("There must be at least 1 file."); } public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) => { var result = await ValidateAsync(ValidationContext<Model>.CreateWithOptions((Model)model, x => x.IncludeProperties(propertyName))); return result.IsValid ? Array.Empty<string>() : result.Errors.Select(e => e.ErrorMessage); }; } }