ColorPicker
JavaScript off: what the HTML and CSS do on their own.
Usage
@* A hex string, with a few colors offered first. *@
<ColorPicker @bind-Value="Model!.Brand" Presets="(["#2563eb", "#0f766e", "#be123c"])" />
@* The swatch alone, for a compact row. *@
<ColorPicker @bind-Value="Model!.Highlight" ShowHex="false" />The value is a hex string such as #2563eb. Underneath is a native color input, so it posts with the form and opens the browser's own color panel with or without the script; the script adds a hex box beside the swatch and the presets as swatches under it. For a few named choices, such as a label's color, a RadioGroup or a SegmentedControl can be clearer.
Presets
Use Presets for the colors to offer first, as hex strings, and PresetText to name them: screen readers hear "Teal" rather than "#0f766e", and the name is the swatch's tooltip.
Preview
Code
System.ComponentModel.DataAnnotations
<Form Model="Model" FormName="color-picker-presets" MaxWidth="20.Rem" Grow>
<ColorPicker @bind-Value="Model!.Brand" Presets="BrandColors.Keys" PresetText="hex => BrandColors[hex]" Hint="Used for buttons, links and focus rings." />
</Form>
{
[SupplyParameterFromForm(FormName = "color-picker-presets")]
private Branding? Model { get; set; }
// Each preset's name, which screen readers hear instead of its hex value. In order.
private static readonly OrderedDictionary<string, string> BrandColors = new()
{
["#2563eb"] = "Blue", ["#4f46e5"] = "Indigo", ["#7c3aed"] = "Violet", ["#0f766e"] = "Teal",
["#15803d"] = "Green", ["#be123c"] = "Rose", ["#ea580c"] = "Orange", ["#18181b"] = "Black",
};
protected override void OnInitialized() => Model ??= new();
public sealed class Branding
{
[Display(Name = "Brand color")]
public string? Brand { get; set; } = "#2563eb";
}
}Off: The swatch fills the field and opens the browser's picker, where Chrome and Edge list the presets first. There's no hex box.
Any color can still be picked or typed, so check the value on the server if it must be one of the presets.
Saving a color
Bind it to a string: the browser sends the color as #rrggbb in lowercase, whether it was picked, chosen from a preset or typed (#F60 becomes #ff6600).
Preview
Code
System.ComponentModel.DataAnnotations
<Form Model="Model" FormName="color-picker-label-color" OnValidSubmit="Save" MaxWidth="20.Rem" Grow>
<TextField @bind-Value="Model!.Name" />
<ColorPicker @bind-Value="Model!.Color" Presets="Colors" />
<Row><Button Submit>Save label</Button></Row>
if (_saved is { } saved)
{
<Row Gap="2" Align="Align.Center">
<TextBlock Size="TextSize.Sm">Saved:</TextBlock>
<Box Width="1.Rem" Height="1.Rem" Radius="Radius.Sm" Border="1" Style="($"background: {saved.Color}")" />
<TextBlock Size="TextSize.Sm">saved.Name, <Code>saved.Color</Code></TextBlock>
</Row>
}
else if (_invalid)
{
<Alert Status="Status.Danger">That isn't a color.</Alert>
}
</Form>
{
[SupplyParameterFromForm(FormName = "color-picker-label-color")]
private IssueLabel? Model { get; set; }
// What was saved, not the fields: on an interactive page they follow each change.
private (string Name, string Color)? _saved;
private bool _invalid;
protected override void OnInitialized() => Model ??= new();
// The browser sends "#rrggbb", but a crafted post can send any text: normalize it, or turn it away.
private void Save()
{
_saved = ColorValues.NormalizeHex(Model!.Color) is { } color ? (Model.Name!, color) : null;
_invalid = _saved is null;
}
private static readonly string[] Colors = ["#be123c", "#ea580c", "#15803d", "#2563eb", "#7c3aed"];
public sealed class IssueLabel
{
[Required, StringLength(24), Display(Name = "Label name")]
public string? Name { get; set; } = "Needs review";
[Display(Name = "Label color")]
public string? Color { get; set; } = "#ea580c";
}
}Off: The swatch opens the browser's panel, with the presets first in Chrome and Edge; Save label posts the color.
The hex box takes three or six hex digits, with or without the #; anything else is put back to the last good value when it loses focus. On a static page the property gets the posted text as it is, and a crafted post can send any text, so pass it through ColorValues.NormalizeHex, which gives #rrggbb or null, before you save or use it, as the example does.
Empty values
A color input always has a value: a property that's null or not a color shows black, and the form posts #000000. Start the property with a color, and treat black as a choice like any other.
Sizes, swatch only and locked
Use Size to line up with other fields, ShowHex="false" for the swatch alone (a read-only picker still shows its hex box, the part that can be focused), ReadOnly for a color that posts but can't change, and Disabled for one that doesn't post.
Preview
Code
System.ComponentModel.DataAnnotations
<Form Model="Model" FormName="color-picker-states" MaxWidth="20.Rem" Grow>
<ColorPicker @bind-Value="Model!.Small" Label="Small" Size="ControlSize.Sm" />
<ColorPicker @bind-Value="Model!.Large" Label="Large" Size="ControlSize.Lg" />
<ColorPicker @bind-Value="Model!.Highlight" ShowHex="false" Hint="Swatch only, with no hex box." />
<ColorPicker @bind-Value="Model!.Brand" ReadOnly Hint="Read-only: posted, but can't be changed." />
<ColorPicker @bind-Value="Model!.Accent" Disabled Hint="Disabled: not posted." />
</Form>
{
[SupplyParameterFromForm(FormName = "color-picker-states")]
private Palette? Model { get; set; }
protected override void OnInitialized() => Model ??= new();
public sealed class Palette
{
public string? Small { get; set; } = "#0f766e";
public string? Large { get; set; } = "#be123c";
public string? Highlight { get; set; } = "#fde68a";
[Display(Name = "Brand color")]
public string? Brand { get; set; } = "#2563eb";
[Display(Name = "Accent color")]
public string? Accent { get; set; } = "#64748b";
}
}Off: There's no hex box, so the read-only field shows only its swatch, disabled.
A read-only color posts from a hidden field, so a crafted post can change it: check it on the server if it matters. A disabled field posts nothing, so after a static post its property is null and the field shows black: keep its value on the server rather than saving it from the post.
Its own words
Use HexLabel for the end of the hex box's name ("Brand color, hex") and PresetsLabel for the presets group ("Preset colors"), or set them for the whole app as in Text and other languages.
Mode support
| Feature | Off | Static | Live |
|---|---|---|---|
| Pick in the browser's color panel; posted with the form | Yes | Yes | Yes |
| A hex box to type or paste in, and preset swatches | No | Yes | Yes |
Off: JavaScript disabled. Static: a static SSR page with IzzyBlazor's script. Live: an interactive page (Server, WebAssembly or Auto).
Accessibility
- The swatch is a native color
input, which opens the browser's own color panel, from the keyboard too, with no script. - With script, the hex box beside it is named after the label and "hex" ("Brand color, hex";
HexLabel). - Presets are buttons in a group named "Preset colors" (
PresetsLabel). Each is named byPresetText("Ocean"), or else by its hex value ("#2563eb"), and pressed (aria-pressed) while it's the value. Name them: a hex value means little to most people. - The hint and errors are linked to both the swatch and the hex box with
aria-describedby, and both setaria-invalidwhen the field is invalid. - Read-only, the swatch and presets are disabled and can't be focused; the hex box is shown, with JavaScript off and with
ShowHexfalse too, and stays focusable and read-only.
Parameters
| Prop | Type | Default |
|---|---|---|
ReadOnlyMakes the field read-only: the hex text can be focused and selected, the swatch and presets are off, and the value still posts. | bool | false |
PresetsColors offered as swatches under the field, as hex strings. | IEnumerable<string>? | |
ShowHexA hex text box beside the swatch (with script), for typing or pasting a value. | bool | true |
HexLabelThe hex box's name after the label. | string? | "hex" |
PresetsLabelThe presets' group name. | string? | "Preset colors" |
PresetTextA name for each preset, such as "Ocean", given the string from Presets. | Func<string, string?>? | |
@bind-ValueThe value, bound with @bind-Value. | string? | |
DisplayNameThe field's name in validation messages from the input itself, such as a value that can't be parsed. | string? |
Plus 26 field props.
Full APISee also
- TextField: a labeled text input with add-ons and a password reveal.
- SegmentedControl: one choice from a few, as joined buttons.
- RadioGroup: one choice from a list of radios.