File Upload

To create a file upload button, two elements are needed: an activator (using the ActivatorContent parameter) and an input.


The MudFileUpload component provides public ClearAsync and OpenFilePickerAsync methods that can be used as OnClick events for buttons.


After uploading the files, you will receive an IReadOnlyList<IBrowserFile> or IBrowserFile and you will need to manually handle the upload in HandleFilesChanged. Instead of using multiple to allow multiple files, you set T to IReadOnlyList<IBrowserFile>. Using IBrowserFile restricts the component to a single file.



Use any type of MudButton

Use a MudButton, a MudIconButton or a MudFab with the ActivatorContent render fragment. A MudFileUpload can be Disabled and it will disable its child button automatically.

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">
                @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.

Note: Some browsers or platforms may require specific values for the Accept attribute.

In MAUI using an Android device for example, you should use Accept="image/png, image/jpg" rather than Accept=".png, .jpg".
Refer to the MAUI docs for more information.

<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="@model" @ref="@form" 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="@ClearAsync">
                            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">
                @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="@false"
                   InputClass="absolute mud-width-full mud-height-full overflow-hidden z-10"
                   InputStyle="opacity:0"
                   tabindex="-1"
                   @ondrop="@ClearDragClass"
                   @ondragenter="@SetDragClass"
                   @ondragleave="@ClearDragClass"
                   @ondragend="@ClearDragClass">
        <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="@file"
                             tabindex="-1" />
                }
            </MudPaper>
        </ActivatorContent>
    </MudFileUpload>
    <MudToolBar Gutters="@false"
                Class="relative d-flex justify-end gap-4">
        <MudButton Color="Color.Primary"
                   OnClick="@OpenFilePickerAsync"
                   Variant="Variant.Filled">
            Open file picker
        </MudButton>
        <MudButton Color="Color.Primary"
                   Disabled="@(!_fileNames.Any())"
                   OnClick="@Upload"
                   Variant="Variant.Filled">
            Upload
        </MudButton>
        <MudButton Color="Color.Error"
                   Disabled="@(!_fileNames.Any())"
                   OnClick="@ClearAsync"
                   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

Drag and drop files here or click
IsValid: False - IsTouched: False
@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="@false"
                           InputClass="absolute mud-width-full mud-height-full overflow-hidden z-10"
                           InputStyle="opacity:0"
                           ErrorText="@string.Empty"
                           tabindex="-1"
                           @ondrop="@ClearDragClass"
                           @ondragenter="@SetDragClass"
                           @ondragleave="@ClearDragClass"
                           @ondragend="@ClearDragClass">
                <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="@file" />
                        }
                    </MudPaper>
                </ActivatorContent>
            </MudFileUpload>
            <MudToolBar Gutters="@false"
                        Class="relative d-flex justify-end gap-4">
                <MudButton Color="Color.Primary"
                           OnClick="@OpenFilePickerAsync"
                           Variant="Variant.Filled">
                    Open file picker
                </MudButton>
                <MudButton Color="Color.Primary"
                           Disabled="@(!_isValid || !_isTouched || _model.Files is null || !_model.Files.Any())"
                           OnClick="@Upload"
                           Variant="Variant.Filled">
                    Upload
                </MudButton>
                <MudButton Color="Color.Error"
                           Disabled="@(_model.Files is null || !_model.Files.Any())"
                           OnClick="@ClearAsync"
                           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);
        };
    }
}
An unhandled error has occurred. Reload 🗙