Skip to content
IzzyBlazor 0.1.0-alpha.17

Enter all results ↑ ↓ move Esc close

Slider

A range input bound to a number.

JavaScript off: what the HTML and CSS do on their own.

Usage

razor
@* 0 to 100, the value shown beside it. *@
<Slider @bind-Value="Model!.Volume" ShowValue />

@* Its own ends and steps, read as a percentage. *@
<Slider @bind-Value="Model!.Discount" Min="0" Max="50" Step="5"
        ShowValue ValueFormat="{0}%" />

It's a native range input, so it posts with the form and moves with the arrow keys, Page Up and Page Down, and Home and End, with or without the script. Use it for a value people judge by eye, such as a volume; when the exact number matters, use a NumberField, or both side by side.

Showing the value

Use ShowValue to show the value beside the slider, and ValueFormat for how it reads, such as "{0}%"; [Range], or Min and Max, set the ends (0 to 100 by default) and Step the increments.

Preview

In steps of 5, up to 50%.

Code

Value.razor
@using System.ComponentModel.DataAnnotations

<Form Model="Model" FormName="slider-value" MaxWidth="24.Rem" Grow>
    <Slider @bind-Value="Model!.Volume" ShowValue />
    <Slider @bind-Value="Model!.Discount" Step="5" ShowValue ValueFormat="{0}%" Hint="In steps of 5, up to 50%." />
</Form>

@code {
    [SupplyParameterFromForm(FormName = "slider-value")]
    private Settings? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    public sealed class Settings
    {
        [Display(Name = "Alert volume")]
        public int Volume { get; set; } = 60;

        [Range(0, 50), Display(Name = "Launch discount")]
        public int Discount { get; set; } = 15;
    }
}

Off: A plain range input: no fill, and no value beside it.

Saving a value

Bind it like any field: the value posts as a number when the form does.

Preview

Ads stop for the month once it's spent.

Code

Budget.razor
@using System.ComponentModel.DataAnnotations

<Form Model="Model" FormName="slider-budget" OnValidSubmit="Save" MaxWidth="24.Rem" Grow>
    <Slider @bind-Value="Model!.Monthly" Step="100" ShowValue ValueFormat="${0}"
            Hint="Ads stop for the month once it's spent." />
    <Row><Button Submit>Save budget</Button></Row>
    @if (_saved is { } saved)
    {
        <Alert Status="Status.Success">Saved: up to $@saved a month.</Alert>
    }
</Form>

@code {
    [SupplyParameterFromForm(FormName = "slider-budget")]
    private Campaign? Model { get; set; }

    // What was saved, not the slider: on an interactive page the slider follows each move.
    private int? _saved;

    protected override void OnInitialized() => Model ??= new();

    private void Save() => _saved = Model!.Monthly;

    public sealed class Campaign
    {
        [Range(0, 5000), Display(Name = "Monthly budget")]
        public int Monthly { get; set; } = 1200;
    }
}

Off: Save budget posts the slider's number; the value beside it doesn't follow the thumb.

The browser keeps the value on a step between the ends, so a post from the page is always in range. A crafted post can send any number: the validator checks [Range] on the server, but not the step, so round the value yourself if it must be a multiple.

Following the value live

Use Live on an interactive page to update the bound value as the thumb moves, rather than when it's let go, for something on the page that follows it.

Always Live

Preview

This example runs C# over a Blazor Server connection, which an Off page doesn't have. Show this page Live

Code

Live.razor
@using System.Globalization

<Form Model="Model" FormName="slider-live" MaxWidth="24.Rem" Grow>
    <Slider @bind-Value="Model!.Opacity" Min="0" Max="1" Step="0.05" ShowValue Live />
    <Box Bg="Color.Primary" Radius="Radius.Md" Height="3.Rem" Style="@($"opacity: {Model!.Opacity.ToString(CultureInfo.InvariantCulture)}")" />
</Form>

@code {
    [SupplyParameterFromForm(FormName = "slider-live")]
    private Overlay? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    public sealed class Overlay
    {
        public double Opacity { get; set; } = 0.8;
    }
}

Each move is a round trip to the server, so use it only when something follows the value. On a static page the value posts when the form does, either way.

Empty values

A range input always has a value: bound to a nullable type that's null, it shows the thumb at the midpoint (snapped to the step) and posts that value. Use a NumberField when "not set" must stay possible.

Sizes and disabled

Use Size to line up with other fields, and Disabled for a value that can't change, which doesn't post. There's no ReadOnly: HTML has no read-only range input, and in a read-only Form the slider is disabled while a hidden field posts its value.

Preview

Disabled: not posted.

Code

States.razor
@using System.ComponentModel.DataAnnotations

<Form Model="Model" FormName="slider-states" MaxWidth="24.Rem" Grow>
    <Slider @bind-Value="Model!.Small" Label="Small" Size="ControlSize.Sm" />
    <Slider @bind-Value="Model!.Large" Label="Large" Size="ControlSize.Lg" />
    <Slider @bind-Value="Model!.Backups" Disabled ShowValue Hint="Disabled: not posted." />
</Form>

@code {
    [SupplyParameterFromForm(FormName = "slider-states")]
    private Plan? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    public sealed class Plan
    {
        public int Small { get; set; } = 30;
        public int Large { get; set; } = 70;

        [Range(0, 30), Display(Name = "Backups kept")]
        public int Backups { get; set; } = 7;
    }
}

Off: Plain range inputs with no values beside them.

A disabled field posts nothing, so after a static post its property holds its default (0, or null): keep its value on the server rather than saving it from the post.

Mode support

What works in each mode, Slider
FeatureOffStaticLive
Drag, arrow keys, Page Up/Down and Home/End; posted with the formYesYesYes
The track fills to the thumb, and the shown value followsNoYesYes
Screen readers hear the value as ValueFormat writes itNoYesYes
The bound value follows while dragging (Live)NoNoYes

Off: JavaScript disabled. Static: a static SSR page with IzzyBlazor's script. Live: an interactive page (Server, WebAssembly or Auto).

Accessibility

  • It renders a native range input (a slider to screen readers): arrow keys, Page Up/Down and Home/End move it with no script.
  • Screen readers hear the value as ValueFormat writes it ("20%", through aria-valuetext) once scripts run or on interactive pages; on a static page without script, the bare number.
  • The value ShowValue shows is hidden from screen readers, which hear the slider's own value.
  • Label, hint and errors work as in TextField.

Parameters

Slider parameters
PropTypeDefault
MinThe lowest value.double?computed
MaxThe highest value.double?computed
StepThe step between values.double?1
ShowValueShows the current value beside the slider.boolfalse
ValueFormatHow the value reads, with {0} for the number: "{0}%", "${0}".string"{0}"
LiveOn interactive pages, update the bound value while dragging rather than on release.boolfalse
@bind-ValueThe value, bound with @bind-Value.TValue
DisplayNameThe field's name in validation messages from the input itself, such as a value that can't be parsed.string?

See also