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.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ButtonExample : Component
{
protected override Component? Render() =>
Ui.Button["Button"];
}Variants
Six ways to draw it. Primary is for the one action a view is about — mostly a form's submit.
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"]
];
}Colors
Any Tailwind hue, as a step. It recolours every variant but danger.
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"]
])
];
}Outline colors
A coloured outline keeps the white surface and mixes the hue into its label, border and hover.
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()])
];
}Sizes
40px, 32px and 24px tall.
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"]
];
}Icons
An icon is a step, so the button pads itself around it. With no label it is a square — name it.
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")
];
}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.
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}"]
];
}Full width
A width class is all it takes.
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"]
];
}Button groups
Related buttons fused into one control: one border between each pair, corners at the two ends.
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")
]
];
}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.
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.
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"]
];
}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.
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")
];
}Reference
Ui.Button
A <button>, or an <a> given Href. Its children are its label.
Step | Takes | What it does |
|---|---|---|
.Variant(…) | Ui.ButtonVariantOutline 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.ButtonSizeBase 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 names | The icon before the label, or with no label the whole button. |
.IconTrailing(…) | Ui.IconName, or a component | What stands after the label: an icon, or content of your own. |
.IconVariant(…) | Ui.IconVariantOutline 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() | bool | As wide as it is tall. Automatic for a button with no children. |
.Align(…) | Ui.AlignDefault 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.InsetNone Top Bottom Left Right All Combined with |. | The sides to pull outwards, so a ghost button lines up with the text around it. |
.Loading() | bool | Whether it shows that it waits. Unset, it does so while its own handler runs past 200 ms. |
.Tooltip(…) | string | A hint shown on hover and focus, which also names a button with no label. |
.TooltipPosition(…) | Ui.TooltipPositionTop 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(…) | string | A shortcut shown at the end of the tooltip: "⌘S". |
.Kbd(…) | string | A shortcut shown inside the button, after its label. |
.Href(…) | a route, or a URL string | Where it goes. A generated route stays in the app; a string is a link the browser follows. |
.Type(…) | Ui.ButtonTypeButton 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.ButtonAsButton 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() | bool | Disables it by attribute, so the browser refuses the press. |
.Command(…) | string | The invoker command run on CommandFor's element: a dialog or popover opened with no script. |
.CommandFor(…) | string | The 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
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.