Rask
Rask
v0.23.1-alpha.0.440

Components

Button

A button is a <button>, or an <a> given Href. Ui.Button.Primary.Sm.Blue is a variant, a size and a colour, each a step; an icon is a step too, so the button pads itself around it.

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

Button

Flux's default is the outline: a white surface, a hairline border, a soft shadow.

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

public sealed partial class ButtonExample : Component
{
    protected override Component? Render() =>
        Ui.Button["Button"];
}
Live result

Variants

Six ways to draw it. Primary is for the one action a view is about — mostly a form's submit.

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

public sealed partial class ButtonVariantsExample : Component
{
    protected override Component? Render() =>
        Div.Class("flex flex-wrap gap-3")[
            Ui.Button["Default"],
            Ui.Button.Primary["Primary"],
            Ui.Button.Filled["Filled"],
            Ui.Button.Danger["Danger"],
            Ui.Button.Ghost["Ghost"],
            Ui.Button.Subtle["Subtle"]
        ];
}
Live result

Colors

Any Tailwind hue, as a step. It recolours every variant but danger.

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

public sealed partial class ButtonColorsExample : Component
{
    private static readonly Ui.Color[] Hues =
    [Ui.Color.Blue, Ui.Color.Red];

    protected override Component? Render() =>
        Div.Class("flex flex-col gap-3")[
            Hues.Select(hue => Div.Key(hue).Class("flex flex-wrap gap-3")[
                Ui.Button.Primary.Color(hue)["Primary"],
                Ui.Button.Filled.Color(hue)["Filled"],
                Ui.Button.Color(hue)["Outline"],
                Ui.Button.Ghost.Color(hue)["Ghost"],
                Ui.Button.Subtle.Color(hue)["Subtle"]
            ])
        ];
}
Live result

Outline colors

A coloured outline keeps the white surface and mixes the hue into its label, border and hover.

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

public sealed partial class ButtonOutlineColorsExample : Component
{
    private static readonly Ui.Color[] Hues =
    [
        Ui.Color.Red, Ui.Color.Orange, Ui.Color.Amber, Ui.Color.Yellow, Ui.Color.Lime, Ui.Color.Green,
        Ui.Color.Emerald, Ui.Color.Teal, Ui.Color.Cyan, Ui.Color.Sky, Ui.Color.Blue, Ui.Color.Indigo,
        Ui.Color.Violet, Ui.Color.Purple, Ui.Color.Fuchsia, Ui.Color.Pink, Ui.Color.Rose,
    ];

    protected override Component? Render() =>
        Div.Class("flex flex-wrap gap-3")[
            Hues.Select(hue => Ui.Button.Key(hue).Color(hue)[hue.ToString()])
        ];
}
Live result

Sizes

40px, 32px and 24px tall.

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

public sealed partial class ButtonSizesExample : Component
{
    protected override Component? Render() =>
        Div.Class("flex flex-wrap items-end gap-3")[
            Ui.Button["Base"],
            Ui.Button.Sm["Small"],
            Ui.Button.Xs["Extra small"]
        ];
}
Live result

Icons

An icon is a step, so the button pads itself around it. With no label it is a square — name it.

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

public sealed partial class ButtonIconsExample : Component
{
    protected override Component? Render() =>
        Div.Class("flex flex-wrap items-center gap-3")[
            Ui.Button.Icon(Ui.IconName.EllipsisHorizontal).AriaLabel("More"),
            Ui.Button.Icon(Ui.IconName.ArrowDownTray)["Export"],
            Ui.Button.IconTrailing(Ui.IconName.ChevronDown)["Open"],
            Ui.Button.Subtle.Icon(Ui.IconName.XMark).AriaLabel("Close"),
            Ui.Button.Icon(Ui.IconName.Plus).Tooltip("Add").TooltipKbd("N")
        ];
}
Live result

Loading

Nothing to set. A button whose handler is still running after 200 ms shows a spinner at the same width, tells a screen reader it is busy and drops a second press. Loading(false) opts a stepper out, so its presses queue.

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

public sealed partial class ButtonLoadingExample : Component
{
    private int _saves;
    private int _steps;

    protected override Component? Render() =>
        Div.Class("flex flex-wrap items-center gap-3")[
            Ui.Button.Primary.OnClick(async () =>
            {
                await Task.Delay(1500);
                _saves++;
            })["Save changes"],
            Ui.Button.Icon(Ui.IconName.Plus).Loading(false).OnClick(async () =>
            {
                await Task.Delay(400);
                _steps++;
            })["Step"],
            Ui.Text.Sm.Inline()[$"Saved {_saves} time{(_saves == 1 ? "" : "s")} · stepped {_steps}"]
        ];
}
Live result
Saved 0 times · stepped 0

Full width

A width class is all it takes.

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

public sealed partial class ButtonFullWidthExample : Component
{
    protected override Component? Render() =>
        Div.Class("max-w-sm")[
            Ui.Button.Primary.Class("w-full")["Send invite"]
        ];
}
Live result

Button groups

Related buttons fused into one control: one border between each pair, corners at the two ends.

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

public sealed partial class ButtonGroupsExample : Component
{
    protected override Component? Render() =>
        Div.Class("flex flex-wrap gap-3")[
            Ui.ButtonGroup[
                Ui.Button["Oldest"],
                Ui.Button["Newest"],
                Ui.Button["Top"]
            ],
            Ui.ButtonGroup[
                Ui.Button.Icon(Ui.IconName.Bars3BottomLeft).Tooltip("Align left"),
                Ui.Button.Icon(Ui.IconName.Bars3).Tooltip("Justify"),
                Ui.Button.Icon(Ui.IconName.Bars3BottomRight).Tooltip("Align right")
            ],
            Ui.ButtonGroup[
                Ui.Button["New product"],
                Ui.Button.Icon(Ui.IconName.ChevronDown).AriaLabel("More options")
            ]
        ];
}
Live result

As a link

Given an Href it is an <a>. A generated route navigates inside the app without reloading it; a plain string is a link the browser follows.

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

public sealed partial class ButtonLinkExample : Component
{
    protected override Component? Render() =>
        Div.Class("flex flex-wrap gap-3")[
            Ui.Button.Href("https://google.com").IconTrailing(Ui.IconName.ArrowUpRight)["Visit Google"],
            Ui.Button.Href(PageMeta.LinkTo(Routes.UiBadgePage()))["See the badge"],
            Ui.Button.Ghost.Href("https://github.com/pal-tamas/rask").Attributes(("target", "_blank"), ("rel", "noopener noreferrer"))["GitHub"]
        ];
}

Square

As wide as it is tall. Automatic for a button that shows only an icon.

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

public sealed partial class ButtonSquareExample : Component
{
    protected override Component? Render() =>
        Div.Class("flex flex-wrap gap-3")[
            Ui.Button.Square()["..."],
            Ui.Button.Disabled()["Disabled"]
        ];
}
Live result

Inset

A ghost button's padding is invisible, so it sits further in than it looks. Inset pulls it back out, in line with the heading.

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

public sealed partial class ButtonInsetExample : Component
{
    protected override Component? Render() =>
        Div.Class("flex max-w-xs items-center justify-between")[
            Ui.Heading["Post successfully created."],
            Ui.Button.Ghost.Sm.Icon(Ui.IconName.XMark).Inset(Ui.Inset.All).AriaLabel("Dismiss")
        ];
}
Live result
Post successfully created.

Reference

Ui.Button

flux:button

A <button>, or an <a> given Href. Its children are its label.

Step
Takes
What it does
.Variant(…)
Ui.ButtonVariant
Outline
Primary
Filled
Danger
Ghost
Subtle

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

How it is drawn. Outline when unset.
.Size(…)
Ui.ButtonSize
Base
Sm
Xs

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

How large it is. Base, 40px tall, when unset.
.Color(…)Ui.Color: one of Tailwind's hues, each a step too (.Blue)A hue for every variant but Danger; a gray changes only Primary.
.Icon(…)Ui.IconName — one of 317 namesThe icon before the label, or with no label the whole button.
.IconTrailing(…)Ui.IconName, or a componentWhat stands after the label: an icon, or content of your own.
.IconVariant(…)
Ui.IconVariant
Outline
Solid
Mini
Micro

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

Which drawing of the icons. Micro beside a label, mini alone, when unset.
.Square()boolAs wide as it is tall. Automatic for a button with no children.
.Align(…)
Ui.Align
Default
Start
Center
End

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

Where the content sits in a button wider than it. Centred when unset.
.Inset(…)
Ui.Inset
None
Top
Bottom
Left
Right
All

Combined with |.

The sides to pull outwards, so a ghost button lines up with the text around it.
.Loading()boolWhether it shows that it waits. Unset, it does so while its own handler runs past 200 ms.
.Tooltip(…)stringA hint shown on hover and focus, which also names a button with no label.
.TooltipPosition(…)
Ui.TooltipPosition
Top
Right
Bottom
Left

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

Which side the tooltip opens on. Above when unset.
.TooltipKbd(…)stringA shortcut shown at the end of the tooltip: "⌘S".
.Kbd(…)stringA shortcut shown inside the button, after its label.
.Href(…)a route, or a URL stringWhere it goes. A generated route stays in the app; a string is a link the browser follows.
.Type(…)
Ui.ButtonType
Button
Submit

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

What a press does: Submit on a form's submit button. Button when unset.
.As(…)
Ui.ButtonAs
Button
A
Div

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

The element to render. Href makes it an <a> without this.
.Disabled()boolDisables it by attribute, so the browser refuses the press.
.Command(…)stringThe invoker command run on CommandFor's element: a dialog or popover opened with no script.
.CommandFor(…)stringThe id of the element Command acts on.

It is one HTML element, so Id, Class, Style, Data, Aria and the events are its steps too.

Ui.ButtonGroup

flux:button.group

Fuses the buttons inside it into one control.

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

It is one HTML element, so Id, Class, Style, Data, Aria and the events are its steps too.