Veto
Components

Rating

A row of icons the user picks a score from - stars by default, any icon you like, and halves that work for all of them.

Basic

Six stars out of the box. Click one to score, click it again to clear. The whole row is a single tab stop that reports itself as a slider, so the arrow keys work and a screen reader hears '3 of 6' once rather than six unrelated buttons.

3 of 6

Six stars by default; Max changes that.

3
razor
<VetoRating TValue="int"
            Label="How was it?"
            ShowValue="true"
            @bind-Value="_score" />

How many icons

Max is the length of the row and so the top score. Five for the familiar scale, ten for a finer one, three when there are only three answers.

2 of 3
7 of 10
razor
<VetoRating TValue="int" Max="3" Label="Out of three" @bind-Value="_a" />
<VetoRating TValue="int" Max="10" Label="Out of ten" @bind-Value="_b" />

Half scores

Set AllowHalf and bind to a fractional type, and the left half of an icon becomes its own target. The half is drawn by clipping a filled copy of the icon over an empty one, so it works for every icon rather than only the ones that ship a purpose-drawn half glyph - the hearts below prove it.

2.5 of 6
3.5 of 6
razor
<VetoRating TValue="double"
            AllowHalf="true"
            Label="Stars"
            ShowValue="true"
            @bind-Value="_score" />

<VetoRating TValue="double"
            AllowHalf="true"
            Icon="@VetoIcons.Heart"
            Color="VetoColor.Danger"
            Label="Hearts"
            @bind-Value="_hearts" />

Any icon

Icon takes any SVG markup - a VetoIcons constant or your own. EmptyIcon draws the unearned slots differently when the shape alone should say 'not yet'.

razor
<VetoRating TValue="int" Icon="@VetoIcons.Bolt" Color="VetoColor.Warning" @bind-Value="_v" />
<VetoRating TValue="int" Icon="@VetoIcons.Circle" Color="VetoColor.Primary" @bind-Value="_v" />
<VetoRating TValue="int" Icon="@VetoIcons.Star" EmptyIcon="@VetoIcons.Circle" @bind-Value="_v" />

Sizes and colours

Three sizes and the library's colour roles. The icons scale with the row's font size, so a rating sits correctly inside any text.

razor
<VetoRating TValue="int" Size="VetoSize.Small" Label="Small" @bind-Value="_v" />
<VetoRating TValue="int" Size="VetoSize.Large" Label="Large" @bind-Value="_v" />
<VetoRating TValue="int" Color="VetoColor.Success" Label="Success" @bind-Value="_v" />

Named scores

ItemLabels names each score. The name goes into the icon's tooltip, its accessible name, and the value a screen reader announces - a number out of six says much less than 'Great'. ShowItemLabel prints the name beside the row, and it follows the pointer while it previews.

4 of 5, Good
razor
<VetoRating TValue="int"
            Max="5"
            ItemLabels="Names"
            ShowItemLabel="true"
            Label="Service"
            @bind-Value="_score" />

@code {
    private static readonly string[] Names =
        ["Terrible", "Poor", "Fair", "Good", "Great"];
}

Read-only and disabled

A read-only rating is the common case - most ratings on a page are being displayed, not collected. Both drop their hit targets entirely rather than merely ignoring clicks.

4.5 of 6
razor
<VetoRating TValue="double" AllowHalf="true" ReadOnly="true" @bind-Value="_average" />
<VetoRating TValue="int" Disabled="true" @bind-Value="_v" />

Validation

Inside an EditForm the rating behaves like any other input: the model's attributes decide what counts, and the message replaces the helper text.

Pick at least one star.

razor
<EditForm Model="_form" OnValidSubmit="Save">
    <DataAnnotationsValidator />

    <VetoRating Label="Score this release"
                Required="true"
                HelperText="Pick at least one star."
                @bind-Value="_form.Score" />

    <button type="submit">Save</button>
</EditForm>

@code {
    private sealed class FormModel
    {
        [Range(1, 6, ErrorMessage = "Pick at least one star.")]
        public int Score { get; set; }
    }
}

Parameters

Parameter Type Default Description
Value TValue default The score. Use @bind-Value. TValue is any number type.
Max int 6 How many icons the row holds, and so the top score.
Icon string VetoIcons.Star The icon the row is drawn from - any SVG markup.
EmptyIcon string? null A different icon for the unearned slots. Defaults to Icon.
AllowHalf bool false Allow half scores. Needs a fractional TValue such as double.
Clearable bool true Picking the current score again clears it back to zero.
HoverPreview bool true Preview the score under the pointer before it is picked.
ShowValue bool false Print the score after the row.
ShowItemLabel bool false Print the ItemLabels name for the score after the row; it follows the pointer while previewing.
ItemLabels IReadOnlyList<string>? null A name per score, used for tooltips and for what is announced.
Color VetoColor Warning The colour the earned icons take.
Size VetoSize Medium ExtraSmall, Small, Medium, Large or ExtraLarge.
Radius string? null Rounds the focus outline's corners, as any CSS length. Null keeps the theme's radius.
RadiusTopLeft / TopRight / BottomRight / BottomLeft string? null One corner's radius, overriding Radius for that corner.
Disabled / ReadOnly / Required bool false The usual input states.
OnValueChanged EventCallback<TValue> — Raised after the score changes.
SetValueAsync(double) Task — Set the score from code; respects Disabled and ReadOnly.
Something went wrong. Reload 🗙