Skip to content
Home Theme Gallery

Button

The custom element is <hui-button>.

Overview

A button in the nova treatment, with shadcn's variant and size API. It carries no form value of its own; type="submit" and type="reset" drive the surrounding form.

Example

Variants
Source
<hui-button>Default</hui-button>
<hui-button variant="secondary">Secondary</hui-button>
<hui-button variant="destructive">Destructive</hui-button>
<hui-button variant="outline">Outline</hui-button>
<hui-button variant="ghost">Ghost</hui-button>
<hui-button variant="link">Link</hui-button>

The Go template that renders it:

{{ range .Variants }}
<hui-button variant="{{ .Name }}">{{ .Label }}</hui-button>
{{ end }}

API

Attributes4
Attributes
NameTypeDefaultDescription
variant"default" | "secondary" | "destructive" | "outline" | "ghost" | "link""default"The visual treatment. An unknown value falls back to default.
size"sm" | "default" | "lg" | "icon" | "icon-sm""default"The height and padding. icon is a 2rem square and icon-sm a 1.75rem one, for a card action or a row menu; both expect an aria-label.
disabledbooleanfalseDisables the internal button, removes it from the tab order and swallows the click.
type"button" | "submit" | "reset""button"Native button behaviour. submit and reset call requestSubmit() and reset() on the ancestor form.
Properties4
Properties
NameTypeDefaultDescription
variantButtonVariant'default'Reflects to the variant attribute.
sizeButtonSize'default'Reflects to the size attribute.
disabledbooleanfalseReflects to the disabled attribute.
typeButtonType'button'Reflects to the type attribute.
Events1
Events
NameDescription
clickThe native click from the internal button. It bubbles and is composed, so an Alpine x-on:click on an ancestor sees it. Suppressed while disabled.
Slots1
Slots
NameDescription
(default)The label and any leading or trailing icon. Inline SVG inherits currentColor.
CSS custom properties3
CSS custom properties
NameDefaultDescription
--hui-primaryoklch(0.496 0.265 301.924)Fill of the default variant.
--hui-radius0.45remBase radius; the button uses --hui-radius-lg.
--hui-focus-ring-width3pxWidth of the keyboard focus ring.
::part() hooks1
::part() hooks
NameDescription
buttonThe internal native <button>. Use ::part(button) for a style no token covers.

States

Sizes

The three sizes beside the icon size. An icon button is square and takes its name from aria-label, because it has no text to read.

Sizes
Source
<hui-button size="sm">Small</hui-button>
<hui-button>Default</hui-button>
<hui-button size="lg">Large</hui-button>
<hui-button size="icon" aria-label="More options">+</hui-button>

Disabled

disabled on two variants. The element forwards it to the button it renders, so the control leaves the tab order and submits nothing.

Disabled
Source
<hui-button disabled>Disabled</hui-button>
<hui-button variant="outline" disabled>Disabled</hui-button>

Server-side mechanics

The server owns the label (the default slot) and the variant, size, type and disabled attributes. It is form-associated only so that type="submit" and type="reset" can call requestSubmit() and reset() on the ancestor form; it carries no value and no name, so it contributes nothing to FormData. An hx-swap may replace the button at any time because it holds no interaction state, so the server only has to re-emit the attributes. There is no validation state for a button, so aria-invalid and hui-field do not apply to it.

Accessibility

  • The accessible name comes from the slotted text or an aria-label; an icon button with neither is a defect.
  • Focus is shown with the shared 3px translucent ring on :focus-visible only, so a mouse click does not draw it.
  • When disabled, the internal button carries the native disabled attribute, so it leaves the tab order as native buttons do.

Keyboard

Keyboard
KeysAction
TabMoves focus to and from the button.
Enter, SpaceActivates the button, exactly as the native control does.

Gotchas

None recorded.