Components
Toggle
A setting turned on or off from a compact, button-shaped control. Use a toggle for icon-sized settings and modes, and a switch when the setting needs a visible label.
Drawn and behaving as Flux UI's toggle does, measured against its live docs.
Toggle
Nobody listens to this one, so the browser turns it and the page is sent nothing.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ToggleExample : Component
{
protected override Component? Render() =>
Ui.Toggle.Icon(Ui.IconName.Bolt).Tooltip("Fast mode");
}Saving changes
Bound, with OnChange to save: the member is written first, and the toggle shows a spinner while the save runs.
using System.Globalization;
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ToggleSavingExample : Component
{
private readonly Project _project = new();
private bool _saved;
private int _saves;
protected override Component? Render() =>
Div.Class("flex flex-wrap items-center gap-3")[
Ui.Toggle.Bind(() => _project.Active).OnChange(Save).Icon(Ui.IconName.LightBulb).Tooltip("Active project"),
Ui.Text.Data("testid", "ui-toggle-saves")[
(_saved ? "Saved as active" : "Saved as inactive") + " · " + _saves.ToString(CultureInfo.InvariantCulture) + " saves"
]
];
// Flux's wire:change="save": the member is written by the time this runs, and the toggle waits on it.
private async Task Save(bool active)
{
await Task.Delay(600);
_saved = active;
_saves++;
}
public sealed class Project
{
public bool Active { get; set; }
}
}Saved as inactive · 0 saves
Sizes
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ToggleSizesExample : Component
{
protected override Component? Render() =>
Div.Class("flex flex-wrap items-center gap-3")[
Ui.Toggle.Icon(Ui.IconName.Bolt),
Ui.Toggle.Icon(Ui.IconName.Bolt).Sm,
Ui.Toggle.Icon(Ui.IconName.Bolt).Xs
];
}Variants
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ToggleVariantsExample : Component
{
protected override Component? Render() =>
Div.Class("flex flex-wrap items-center gap-3")[
Ui.Toggle.Icon(Ui.IconName.Bolt),
Ui.Toggle.Icon(Ui.IconName.Bolt).Filled,
Ui.Toggle.Icon(Ui.IconName.Bolt).Ghost,
Ui.Toggle.Icon(Ui.IconName.Bolt).Subtle
];
}Color
The colour of the icon when on. Off, it stays neutral.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ToggleColorExample : Component
{
protected override Component? Render() =>
Div.Class("flex flex-wrap items-center gap-3")[
Ui.Toggle.Icon(Ui.IconName.Bolt).Color(Ui.Color.Blue).Checked(),
Ui.Toggle.Icon(Ui.IconName.Heart).Color(Ui.Color.Red).Checked(),
Ui.Toggle.Icon(Ui.IconName.Bell).Color(Ui.Color.Amber).Checked()
];
}With label
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ToggleLabelExample : Component
{
protected override Component? Render() =>
Ui.Toggle.Icon(Ui.IconName.Bolt).Label("Fast mode");
}Stateful icon
A different icon for each state, kept by the page.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ToggleStatefulIconExample : Component
{
private bool _sound;
protected override Component? Render() =>
Div.Class("flex flex-wrap items-center gap-3")[
Ui.Toggle.OnIcon(Ui.IconName.SpeakerWave).OffIcon(Ui.IconName.SpeakerXMark).Tooltip("Toggle sound")
.Checked(_sound).OnChange(on => { _sound = on; }),
Ui.Text.Data("testid", "ui-toggle-sound")[_sound ? "Playing" : "Muted"]
];
}Muted
Custom icons
Icons of your own, each shown for its state with group-data-checked:.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ToggleCustomIconsExample : Component
{
// Lucide's shrink and expand, as Flux's page imports them: each drawn for its own state with group-data-checked.
private const string Lucide =
" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\""
+ " stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">";
private const string Shrink =
"<svg class=\"size-5 hidden group-data-checked:block text-accent-content\"" + Lucide
+ "<path d=\"m15 15 6 6m-6-6v4.8m0-4.8h4.8\"/><path d=\"M9 19.8V15m0 0H4.2M9 15l-6 6\"/>"
+ "<path d=\"M15 4.2V9m0 0h4.8M15 9l6-6\"/><path d=\"M9 4.2V9m0 0H4.2M9 9 3 3\"/></svg>";
private const string Expand =
"<svg class=\"size-5 group-data-checked:hidden text-zinc-500/85 dark:text-zinc-300/80\"" + Lucide
+ "<path d=\"m15 15 6 6\"/><path d=\"m15 9 6-6\"/><path d=\"M21 16v5h-5\"/><path d=\"M21 8V3h-5\"/>"
+ "<path d=\"M3 16v5h5\"/><path d=\"m3 21 6-6\"/><path d=\"M3 8V3h5\"/><path d=\"M9 9 3 3\"/></svg>";
protected override Component? Render() =>
Ui.Toggle.Icon(Raw.Value(Shrink + Expand)).Tooltip("Toggle fullscreen");
}Stateful label
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ToggleStatefulLabelExample : Component
{
protected override Component? Render() =>
Ui.Toggle.OnLabel("Sound on").OffLabel("Sound off");
}Disabled
Dimmed, and out of the tab order.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ToggleDisabledExample : Component
{
protected override Component? Render() =>
Ui.Toggle.Icon(Ui.IconName.Bolt).Label("Fast mode").Disabled();
}Behaviour
A real switch
It is a <button role="switch">: a press, Space and Enter turn it, and a screen reader says "on" or "off". A toggle that shows only an icon is named by its Tooltip. Icon draws a Heroicon's outline when off and its solid drawing when on, and OnIcon, OffIcon, OnLabel and OffLabel say each state apart.
Whose state it is
Bind two-way binds a bool: the member is written with the next action, as every kit control's is, and at once with .Live(). A bound toggle the page listens to with OnChange is written at once too, and OnChange runs after the write: Flux's wire:model beside wire:change, one round trip that saves. While its handler runs the runtime marks the button data-loading: what it shows gives way to a spinner and it takes no further press.
Unbound and listened to with OnChange, it reports each turn, and a page that hands it a different Checked has the last word.
A toggle nobody listens to sends nothing
With no Bind and no OnChange a press only changes what the toggle draws, so the browser does it (data-rask-switch): aria-checked and data-checked flip there, and not one frame goes to the page. Checked is then where it starts.
Reference
Ui.Toggle
A setting turned on or off from a compact button. Its children, when it has any, are its label.
Step | Takes | What it does |
|---|---|---|
.Bind(…) | () => a bool | The bool it reads and writes: () => m.FastMode. |
.OnChange(…) | a handler given the state it is now in: open => … | Runs with the new state at each turn, after the write when it is bound: Flux's wire:change. |
.Live() | bool | Writes the model as soon as it is turned, not with the next action. |
.Checked() | bool | Whether it is on, for a toggle that is not bound: where it starts. |
.Icon(…) | Ui.IconName, or a component | A Heroicon, outlined when off and solid when on, or icons of your own. |
.OnIcon(…) | Ui.IconName — one of 317 names | The icon shown when on, in place of Icon. |
.OffIcon(…) | Ui.IconName — one of 317 names | The icon shown when off, in place of Icon. |
.Label(…) | string | Words beside the icon, in both states. |
.OnLabel(…) | string | The words shown when on. |
.OffLabel(…) | string | The words shown when off. |
.Size(…) | Ui.ToggleSizeBase Sm Xs Each is a step of its own too, unless an HTML tag has its name. | How large it is. Base, 40px, when unset. |
.Variant(…) | Ui.ToggleVariantOutline Filled Ghost Subtle Each is a step of its own too, unless an HTML tag has its name. | How it is drawn. Outline when unset. |
.Color(…) | Ui.Color: one of Tailwind's hues, each a step too (.Blue) | The icon's colour when on. The accent when unset. |
.Tooltip(…) | string | A hint on hover, which also names a toggle that shows only an icon. |
.Disabled() | bool | Dimmed, and out of the tab order. |