Rask
Rask
v0.23.1-alpha.0.478

Components

Radio

One option from a set that excludes the others. The group binds one value, of any type, and each radio says what the value becomes when it is chosen.

Drawn and behaving as Flux UI's radio does, measured against its live docs.

Radio

RadioExample.cs
namespace Rask.Site.Features.UiDocs.Examples;

public sealed partial class RadioExample : Component
{
    private string Payment { get; set; } = "cc";

    protected override Component? Render() =>
        Div.Class("space-y-3")[
            Ui.RadioGroup.Bind(() => Payment).Live().Id("rd-payment").Label("Select your payment method")[
                Ui.Radio.Value("cc").Label("Credit Card"),
                Ui.Radio.Value("paypal").Label("Paypal"),
                Ui.Radio.Value("ach").Label("Bank transfer")
            ],
            Ui.Text.Data("testid", "ui-radio-state")[$"Paying by {Payment}."]
        ];
}
Live result

Paying by cc.

With descriptions

A description sits under each radio's label.

RadioDescriptionsExample.cs
namespace Rask.Site.Features.UiDocs.Examples;

public sealed partial class RadioDescriptionsExample : Component
{
    private string Role { get; set; } = "administrator";

    protected override Component? Render() =>
        Ui.RadioGroup.Bind(() => Role).Label("Role")[
            Ui.Radio.Value("administrator").Label("Administrator").Description("Administrator users can perform any action."),
            Ui.Radio.Value("editor").Label("Editor").Description("Editor users have the ability to read, create, and update."),
            Ui.Radio.Value("viewer").Label("Viewer")
                .Description("Viewer users only have the ability to read. Create, and update are restricted.")
        ];
}
Live result
Administrator users can perform any action.
Editor users have the ability to read, create, and update.
Viewer users only have the ability to read. Create, and update are restricted.

Within fieldset

The group inside a fieldset, whose legend names it.

RadioFieldsetExample.cs
namespace Rask.Site.Features.UiDocs.Examples;

public sealed partial class RadioFieldsetExample : Component
{
    private string Role { get; set; } = "administrator";

    protected override Component? Render() =>
        Ui.Fieldset[
            Ui.Legend["Role"],
            Ui.RadioGroup.Bind(() => Role)[
                Ui.Radio.Value("administrator").Label("Administrator").Description("Administrator users can perform any action."),
                Ui.Radio.Value("editor").Label("Editor").Description("Editor users have the ability to read, create, and update."),
                Ui.Radio.Value("viewer").Label("Viewer")
                    .Description("Viewer users only have the ability to read. Create, and update are restricted.")
            ]
        ];
}
Live result
Role
Administrator users can perform any action.
Editor users have the ability to read, create, and update.
Viewer users only have the ability to read. Create, and update are restricted.

Segmented

A more compact row of the same radios.

RadioSegmentedExample.cs
namespace Rask.Site.Features.UiDocs.Examples;

public sealed partial class RadioSegmentedExample : Component
{
    private string Role { get; set; } = "administrator";

    protected override Component? Render() =>
        Div.Class("space-y-3")[
            Ui.RadioGroup.Bind(() => Role).Live().Id("rd-segmented").Label("Role").Segmented[
                Ui.Radio.Value("administrator").Label("Admin"),
                Ui.Radio.Value("editor").Label("Editor"),
                Ui.Radio.Value("viewer").Label("Viewer")
            ],
            Ui.Text.Data("testid", "ui-radio-segmented-state")[$"Role: {Role}."]
        ];
}
Live result

Role: administrator.

Small segmented

RadioSegmentedSmallExample.cs
namespace Rask.Site.Features.UiDocs.Examples;

public sealed partial class RadioSegmentedSmallExample : Component
{
    private string Role { get; set; } = "administrator";

    protected override Component? Render() =>
        Ui.RadioGroup.Bind(() => Role).Label("Role").Segmented.Sm[
            Ui.Radio.Value("administrator").Label("Admin"),
            Ui.Radio.Value("editor").Label("Editor"),
            Ui.Radio.Value("viewer").Label("Viewer")
        ];
}
Live result

Segmented with icons

RadioSegmentedIconsExample.cs
namespace Rask.Site.Features.UiDocs.Examples;

public sealed partial class RadioSegmentedIconsExample : Component
{
    private string Role { get; set; } = "administrator";

    protected override Component? Render() =>
        Ui.RadioGroup.Bind(() => Role).Segmented[
            Ui.Radio.Value("administrator").Label("Admin").Icon(Ui.IconName.Wrench),
            Ui.Radio.Value("editor").Label("Editor").Icon(Ui.IconName.PencilSquare),
            Ui.Radio.Value("viewer").Label("Viewer").Icon(Ui.IconName.Eye)
        ];
}
Live result

Radio cards

A bordered card is the radio: a press anywhere on it chooses it. max-sm:flex-col stacks the cards on a phone.

RadioCardsExample.cs
namespace Rask.Site.Features.UiDocs.Examples;

public sealed partial class RadioCardsExample : Component
{
    private string Shipping { get; set; } = "standard";

    protected override Component? Render() =>
        Div.Class("space-y-3")[
            Ui.RadioGroup.Bind(() => Shipping).Live().Id("rd-cards").Label("Shipping").Cards.Class("max-sm:flex-col")[
                Ui.Radio.Value("standard").Label("Standard").Description("4-10 business days"),
                Ui.Radio.Value("fast").Label("Fast").Description("2-5 business days"),
                Ui.Radio.Value("next-day").Label("Next day").Description("1 business day")
            ],
            Ui.Text.Data("testid", "ui-radio-cards-state")[$"Shipping {Shipping}."]
        ];
}
Live result

Shipping standard.

Vertical cards

RadioVerticalCardsExample.cs
namespace Rask.Site.Features.UiDocs.Examples;

public sealed partial class RadioVerticalCardsExample : Component
{
    private string Shipping { get; set; } = "standard";

    protected override Component? Render() =>
        Ui.RadioGroup.Bind(() => Shipping).Label("Shipping").Cards.Class("max-w-md flex-col")[
            Ui.Radio.Value("standard").Label("Standard").Description("4-10 business days"),
            Ui.Radio.Value("fast").Label("Fast").Description("2-5 business days"),
            Ui.Radio.Value("next-day").Label("Next day").Description("1 business day")
        ];
}
Live result

Cards with icons

RadioCardIconsExample.cs
namespace Rask.Site.Features.UiDocs.Examples;

public sealed partial class RadioCardIconsExample : Component
{
    private string Shipping { get; set; } = "standard";

    protected override Component? Render() =>
        Ui.RadioGroup.Bind(() => Shipping).Label("Shipping").Cards.Class("max-sm:flex-col")[
            Ui.Radio.Value("standard").Icon(Ui.IconName.Truck).Label("Standard").Description("4-10 business days"),
            Ui.Radio.Value("fast").Icon(Ui.IconName.Cube).Label("Fast").Description("2-5 business days"),
            Ui.Radio.Value("next-day").Icon(Ui.IconName.Clock).Label("Next day").Description("1 business day")
        ];
}
Live result

Cards without indicators

Indicator(false) leaves the dot out, for a cleaner card.

RadioBareCardsExample.cs
namespace Rask.Site.Features.UiDocs.Examples;

public sealed partial class RadioBareCardsExample : Component
{
    private string Shipping { get; set; } = "standard";

    protected override Component? Render() =>
        Ui.RadioGroup.Bind(() => Shipping).Label("Shipping").Cards.Indicator(false).Class("max-sm:flex-col")[
            Ui.Radio.Value("standard").Icon(Ui.IconName.Truck).Label("Standard").Description("4-10 business days"),
            Ui.Radio.Value("fast").Icon(Ui.IconName.Cube).Label("Fast").Description("2-5 business days"),
            Ui.Radio.Value("next-day").Icon(Ui.IconName.Clock).Label("Next day").Description("1 business day")
        ];
}
Live result

Custom card content

A card's children replace its label and description; Ui.RadioIndicator puts the dot among them.

RadioCustomCardsExample.cs
namespace Rask.Site.Features.UiDocs.Examples;

public sealed partial class RadioCustomCardsExample : Component
{
    private string Shipping { get; set; } = "standard";

    protected override Component? Render() =>
        Ui.RadioGroup.Bind(() => Shipping).Label("Shipping").Cards.Class("max-sm:flex-col")[
            Ui.Radio.Value("standard")[
                Ui.RadioIndicator,
                Div.Class("flex-1")[
                    Ui.Heading.Class("leading-4")["Standard"],
                    Ui.Text.Sm.Class("mt-2")["4-10 business days"]
                ]
            ],
            Ui.Radio.Value("fast")[
                Ui.RadioIndicator,
                Div.Class("flex-1")[
                    Ui.Heading.Class("leading-4")["Fast"],
                    Ui.Text.Sm.Class("mt-2")["2-5 business days"]
                ]
            ],
            Ui.Radio.Value("next-day")[
                Ui.RadioIndicator,
                Div.Class("flex-1")[
                    Ui.Heading.Class("leading-4")["Next day"],
                    Ui.Text.Sm.Class("mt-2")["1 business day"]
                ]
            ]
        ];
}
Live result

Pills

RadioPillsExample.cs
namespace Rask.Site.Features.UiDocs.Examples;

public sealed partial class RadioPillsExample : Component
{
    private string Priority { get; set; } = "medium";

    protected override Component? Render() =>
        Ui.RadioGroup.Bind(() => Priority).Label("Priority").Pills[
            Ui.Radio.Value("low").Label("Low"),
            Ui.Radio.Value("medium").Label("Medium"),
            Ui.Radio.Value("high").Label("High"),
            Ui.Radio.Value("critical").Label("Critical")
        ];
}
Live result

Buttons

Radios drawn as a toolbar. A radio's children are its words, as a button's are.

RadioButtonsExample.cs
namespace Rask.Site.Features.UiDocs.Examples;

public sealed partial class RadioButtonsExample : Component
{
    private string Feedback { get; set; } = "bug";

    protected override Component? Render() =>
        Ui.RadioGroup.Bind(() => Feedback).Buttons.Class("w-full *:flex-1").Label("Feedback type")[
            Ui.Radio.Value("bug").Icon(Ui.IconName.BugAnt)["Bug report"],
            Ui.Radio.Value("suggestion").Icon(Ui.IconName.LightBulb)["Suggestion"],
            Ui.Radio.Value("question").Icon(Ui.IconName.QuestionMarkCircle)["Question"]
        ];
}
Live result

Behaviour

One value, of any type

The group binds one value: Ui.RadioGroup.Bind(() => m.Plan) over a string, an enum or a number, or Value(plan).OnChange(…) for one the page owns. Each Ui.Radio's Value is what the member becomes when that radio is chosen, and Ui.Radio.Checked() chooses one only while the group holds no value. Segmented (with Sm), Cards (with Indicator(false)), Pills and Buttons draw the same radios.

The keyboard

Each radio is a <label> around a real <input type="radio"> that shares the group's name, so the keys are the browser's in every variant, and so are a click on the label and the form post.

Key
What happens
ArrowDown, ArrowRightMoves to the next radio and chooses it, wrapping from the last to the first.
ArrowUp, ArrowLeftMoves to the previous radio and chooses it, wrapping from the first to the last.
TabEnters the group at the chosen radio, and leaves it.
SpaceChooses the focused radio.

What it posts

A radio group names its radios after its own id unless Name says otherwise, and a Name on one radio replaces the group's for that radio. A bound group is invalid on its own while its form holds a message for the member, and Invalid() says so by hand.

Reference

Ui.RadioGroup

flux:radio.group

Radios over one value. Its type is the type of their values.

Step
Takes
What it does
.Bind(…)() => a TThe model's member it reads and writes: () => m.Plan. Or Value with OnChange.
.Value(…)T, the type of the radios' valuesThe chosen value, for a page that holds it itself.
.OnChange(…)a handler given the new valueRuns with the new value when a radio is chosen.
.AfterBind(…)a handler given the new valueRuns after Bind has written the model.
.Validate(…)a validatorA rule the value is checked by when it is written.
.Live()boolWrites the model as soon as a radio is chosen, not with the next action.
.Variant(…)
Ui.RadioGroupVariant
Default
Segmented
Cards
Pills
Buttons

Each is a step of its own too, unless an HTML tag has its name.

How the radios are drawn. A column when unset.
.Size(…)
Ui.RadioGroupSize
Base
Sm

Each is a step of its own too, unless an HTML tag has its name.

Sm for a smaller segmented row.
.Indicator()boolFalse leaves the dot off the cards.
.Label(…)stringDraws a field around it, with this label and the error.
.Description(…)stringHelp text between the label and the radios.
.Invalid()boolError styling the form did not ask for.
.Name(…)stringWhat the radios are posted under. The group's id when unset.
.ShowValidation()boolFalse leaves the member's message to a Ui.Error placed elsewhere.

Ui.Radio

flux:radio

One choice in a label. Its children are a button's words, or a custom card.

Step
Takes
What it does
.Value(…)a value of the group's typeWhat the group's member becomes when it is chosen.
.Label(…)stringIts words, beside it.
.Description(…)stringHelp text under its label.
.Icon(…)Ui.IconName — one of 317 namesAn icon on a segment, a card or a button.
.Checked()boolChooses it while the group holds no value.
.Disabled()boolDims it and takes it out of reach.
.Name(…)stringWhat it is posted under, in place of the group's.
.Attributes(…)("aria-label", "Search") pairsAttributes for the <input> itself.

Ui.RadioIndicator

flux:radio.indicator

The dot, placed among a custom card's own content.

No steps of its own: what goes inside it is its content.

Confirm