Infinite UI Demo

Infinite UI is a collection of reusable components for building elegant user interfaces in Go.
It is built with a-h/templ, Alpine.js, Tailwind CSS, Phosphor Icons and the occasional additional JavaScript libraries when necessary.

GitHub Repository GitHub Discussions Reddit Subreddit Quality Gate Status License

@uiForm

uiForm is a collection of components that make it easy to create forms.

.CheckboxInput

A checkbox selects one value, bound to a boolean or an array state path.

Usage

@uiForm.CheckboxInput(uiForm.CheckboxInputSettings{
	Label:           "Accept the terms",
	TwoWayStatePath: "hasAcceptedTerms",

	// OptionalFields
	InputName: "hasAcceptedTerms",
})
Alpine.js Parent State (x-data)
<div x-data="{hasAcceptedTerms: false}"></div>
<div x-data="{selectedFruits: ['apple']}"></div>

Live Example

A bound checkbox and the select-all pattern with an indeterminate parent.

Boolean state

Value:

Indeterminate state

Values:

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Shapes
Shapes

Shape rounds the checkbox frame: square, rounded, or circular.

Usage

@uiForm.CheckboxInput(uiForm.CheckboxInputSettings{
	Label:           "Accept the terms",
	TwoWayStatePath: "hasAcceptedTerms",

	// OptionalFields
	Shape: uiForm.CheckboxInputShapeRounded,
})
Sizes
Sizes

Size scales the checkbox and its label: xs, sm, md, lg, or xl.

Usage

@uiForm.CheckboxInput(uiForm.CheckboxInputSettings{
	Label:           "Accept the terms",
	TwoWayStatePath: "hasAcceptedTerms",

	// OptionalFields
	Size: uiForm.CheckboxInputSizeMd,
})
Label Position
Label Position

LabelPosition places the label on the left or the right of the checkbox.

Usage

@uiForm.CheckboxInput(uiForm.CheckboxInputSettings{
	Label:           "Accept the terms",
	TwoWayStatePath: "hasAcceptedTerms",

	// OptionalFields
	LabelPosition: uiForm.CheckboxInputLabelPositionLeft,
})
States
States

IsChecked starts the box checked, IsDisabled blocks edits, and IsRequired marks the field as required.

Usage

@uiForm.CheckboxInput(uiForm.CheckboxInputSettings{
	Label: "Accept the terms",

	// OptionalFields
	IsChecked:  true,
	IsDisabled: false,
	IsRequired: false,
})
Error States
Error States

IsInvalid shows the error style and ErrorMessage explains it. IsInvalidOneWayStatePath drives the error from Alpine state.

Usage

@uiForm.CheckboxInput(uiForm.CheckboxInputSettings{
	Label: "Accept the terms",

	// OptionalFields
	IsInvalid:                 true,
	ErrorMessage:              "You must accept the terms to continue.",
	IsInvalidOneWayStatePath:  "!hasAcceptedTerms",
})
You must accept the terms to continue.
Checking the box clears this error.
Checked Colors
Checked Colors

CheckedColor paints the filled box. UncheckedColor paints the empty box.

Usage

@uiForm.CheckboxInput(uiForm.CheckboxInputSettings{
	Label: "Primary",

	// OptionalFields
	IsChecked:    true,
	CheckedColor: "primary-500",
})

.InlineRadioGroup

An inline radio group displays a set of radio options in a horizontal layout.

Usage

@uiForm.InlineRadioGroup(uiForm.InlineRadioGroupSettings{
	Label: "Select an option",
	InputSettings: []uiForm.RadioInputSettings{
		{
			Label:           "Option 1",
			StateValue:      "option1",
			TwoWayStatePath: "groupSelection",
			InputId:         "groupOption1",
			InputName:       "group1",
		},
	},

	// OptionalFields
	TwoWayStatePath: "groupSelection",
})
Alpine.js Parent State (x-data)
<div x-data="{groupSelection: 'option2'}"></div>

Live Example

A horizontal radio group bound to one shared Alpine state path.

Select an option

Value:

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Sizes
Sizes

Each radio carries its own Size, so the group can scale per option.

Usage

@uiForm.InlineRadioGroup(uiForm.InlineRadioGroupSettings{
	Label: "Select an option",
	InputSettings: []uiForm.RadioInputSettings{
		{
			Label:           "Option 1",
			StateValue:      "option1",
			TwoWayStatePath: "groupSelection",
			Size:            uiForm.RadioInputSizeSm,
		},
	},
})

Pick a size

.InputField

An input field is a basic form element that allows users to enter text.

Usage

@uiForm.InputField(uiForm.InputFieldSettings{
	InputType: uiForm.InputTypeText,
	InputName: "name",
	Label:     "Name",

	// OptionalFields
	TwoWayStatePath: "name",
})
Alpine.js Parent State (x-data)
<div x-data="{name: ''}"></div>

Live Example

A labeled text field bound to Alpine state.

Name

Value:

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Value & Read-Only
Value & Read-Only

Value seeds the field content. IsReadOnly shows the value without accepting edits.

Usage

@uiForm.InputField(uiForm.InputFieldSettings{
	InputType: uiForm.InputTypeText,
	InputName: "name",
	Label:     "Name",

	// OptionalFields
	Value:      "Lorem ipsum dolor sit amet.",
	IsReadOnly: true,
})
Name
Number Constraints
Number Constraints

InputTypeNumber with InputNumberMin, InputNumberMax, and InputNumberStep bounds the accepted value.

Usage

@uiForm.InputField(uiForm.InputFieldSettings{
	InputType: uiForm.InputTypeNumber,
	InputName: "name",
	Label:     "Name",

	// OptionalFields
	TwoWayStatePath: "name",
	InputNumberMin:  "0",
	InputNumberMax:  "100",
	InputNumberStep: ".1",
})
Name
Affixes
Affixes

AffixLeftValue and AffixRightValue render fixed text on either side of the input.

Usage

@uiForm.InputField(uiForm.InputFieldSettings{
	InputType: uiForm.InputTypeText,
	InputName: "name",
	Label:     "Name",

	// OptionalFields
	TwoWayStatePath: "name",
	AffixLeftValue:  "goinfinite.net/",
	AffixRightValue: ".jpg",
})
Name
goinfinite.net/
Name
.jpg
Slug
ui.demo.goinfinite.net
Affix Width
Affix Width

AffixLeftWidthPercent and AffixRightWidthPercent fix an affix to a percentage of the field width. Without them, an affix caps at half the width.

Usage

@uiForm.InputField(uiForm.InputFieldSettings{
	InputType: uiForm.InputTypeText,
	InputName: "domain",
	Label:     "Domain",

	// OptionalFields
	TwoWayStatePath:       "domain",
	AffixLeftValue:        "goinfinite.net/",
	AffixLeftWidthPercent: 40,
})
Domain
goinfinite.net/
Name
.jpg
Sizes
Sizes

Size scales the input, its affixes, and the floating label. It accepts xs, sm, md (the default), lg, or xl.

Usage

@uiForm.InputField(uiForm.InputFieldSettings{
	InputType: uiForm.InputTypeText,
	InputName: "name",
	Label:     "Name",

	// OptionalFields
	Size: uiForm.InputFieldSizeLg,
})
Name (xs)
Name (sm)
Name (md)
Name (lg)
Name (xl)
Label Case
Label Case

TextCase transforms the floating label and the placeholder. It accepts uiToolset.TextCaseNone (the default, as typed), TextCaseLower, TextCaseUpper, or TextCaseCapitalize.

Usage

@uiForm.InputField(uiForm.InputFieldSettings{
	InputType: uiForm.InputTypeText,
	InputName: "name",
	Label:     "Network Interface",

	// OptionalFields
	TextCase: uiToolset.TextCaseUpper,
})
Network Interface (none)
Network Interface (lower)
Network Interface (upper)
Network Interface (capitalize)
Hints
Hints

HintValue explains the field. HintDisplay shows it as a description below the field or as a tooltip.

Usage

@uiForm.InputField(uiForm.InputFieldSettings{
	InputType: uiForm.InputTypeText,
	InputName: "name",
	Label:     "Name",

	// OptionalFields
	TwoWayStatePath: "name",
	HintValue:       "This is a helpful hint.",
	HintDisplay:     uiForm.InputHintDisplayDescription,
})
Name
This is a helpful hint displayed as a description below the input.
Name
Hint Icon Styles
Hint Icon Styles

HintIconStyle renders the hint trigger as an icon or as a boxed tooltip.

Usage

@uiForm.InputField(uiForm.InputFieldSettings{
	InputType: uiForm.InputTypeText,
	InputName: "name",
	Label:     "Name",

	// OptionalFields
	TwoWayStatePath: "name",
	HintValue:       "This is a helpful hint.",
	HintDisplay:     uiForm.InputHintDisplayTooltip,
	HintIconStyle:   uiForm.InputHintIconStyleBoxed,
})
Name

.MultiSelectInput

A multi-select input allows users to select multiple options from a dropdown list.

Usage

@uiForm.MultiSelectInput(uiForm.MultiSelectInputSettings{
	InputName: "countries",
	Label:     "Countries",

	// OptionalFields
	FlatOptions:     []string{"Argentina", "Brazil", "Chile"},
	TwoWayStatePath: "countries",
})
Alpine.js Parent State (x-data)
<div x-data="{countries: ['Brazil']}"></div>

Live Example

A multi-select bound to an Alpine array, with flat option labels.

Countries
Countries

Values:

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

LabelValueOptions
LabelValueOptions

LabelValueOptions send a stored Value while showing a human Label. The bound state holds the selected Values.

Usage

@uiForm.MultiSelectInput(uiForm.MultiSelectInputSettings{
	InputName: "countries",
	Label:     "Countries",

	// OptionalFields
	LabelValueOptions: []uiForm.SelectLabelValueOption{
		{Label: "Argentina", Value: "AR"},
		{Label: "Brazil", Value: "BR"},
		{Label: "Chile", Value: "CL"},
	},
	TwoWayStatePath: "countries",
})
Alpine.js Parent State (x-data)
<div x-data="{countries: ['BR']}"></div>
Countries
Countries
HTML Option Labels
HTML Option Labels

LabelHtml replaces the plain option label with custom markup in the dropdown.

Usage

@uiForm.MultiSelectInput(uiForm.MultiSelectInputSettings{
	InputName: "countriesWithHtml",
	Label:     "Countries",

	// OptionalFields
	LabelValueOptions: []uiForm.SelectLabelValueOption{
		{Label: "Argentina", LabelHtml: MultiSelectInputDemoOption1(), Value: "AR"},
		{Label: "Brazil", LabelHtml: MultiSelectInputDemoOption2(), Value: "BR"},
		{Label: "Chile", LabelHtml: MultiSelectInputDemoOption3(), Value: "CL"},
	},
	TwoWayStatePath: "countries",
})
Alpine.js Parent State (x-data)
<div x-data="{countries: ['BR']}"></div>

Click the dropdown to see the HTML labels.

Countries
Countries
Hints
Hints

HintValue explains the field. HintDisplay shows it as a description below the field or as a tooltip.

Usage

@uiForm.MultiSelectInput(uiForm.MultiSelectInputSettings{
	InputName: "countriesHint",
	Label:     "Countries",

	// OptionalFields
	FlatOptions:     []string{"Argentina", "Brazil", "Chile"},
	TwoWayStatePath: "countries",
	HintValue:        "This is a helpful hint.",
	HintDisplay:      uiForm.InputHintDisplayDescription,
})
Countries
Countries
This is a helpful hint displayed as a description below the multi-select.
Countries
Countries
Hint Icon Styles
Hint Icon Styles

HintIconStyle renders the hint trigger as an icon or as a boxed tooltip.

Usage

@uiForm.MultiSelectInput(uiForm.MultiSelectInputSettings{
	InputName: "countriesHintBoxed",
	Label:     "Countries",

	// OptionalFields
	FlatOptions:     []string{"Argentina", "Brazil", "Chile"},
	TwoWayStatePath: "countries",
	HintValue:        "This is a helpful hint.",
	HintDisplay:      uiForm.InputHintDisplayTooltip,
	HintIconStyle:    uiForm.InputHintIconStyleBoxed,
})
Countries
Countries
Required
Required

IsRequired marks the field as required.

Usage

@uiForm.MultiSelectInput(uiForm.MultiSelectInputSettings{
	InputName: "countriesRequired",
	Label:     "Countries",

	// OptionalFields
	FlatOptions:     []string{"Argentina", "Brazil", "Chile"},
	TwoWayStatePath: "countries",
	IsRequired:      true,
})
Countries *
Countries

.RadioInput

A radio input allows users to select one option from a set of options.

Usage

@uiForm.RadioInput(uiForm.RadioInputSettings{
	Label:           "Option 1",
	StateValue:      "option1",
	TwoWayStatePath: "selectedOption",
	InputId:         "radioOption1",
	InputName:       "options",
})
Alpine.js Parent State (x-data)
<div x-data="{selectedOption: 'option2'}"></div>

Live Example

A radio group bound to one shared Alpine state path.

Value:

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Sizes
Sizes

Size scales the radio and its label: xs, sm, md, lg, or xl.

Usage

@uiForm.RadioInput(uiForm.RadioInputSettings{
	Label:           "Option 1",
	StateValue:      "option1",
	TwoWayStatePath: "selectedOption",

	// OptionalFields
	Size: uiForm.RadioInputSizeMd,
})

.SelectInput

A select input allows users to select one option from a dropdown list.

Usage

@uiForm.SelectInput(uiForm.SelectInputSettings{
	InputName: "country",
	Label:     "Country",

	// OptionalFields
	FlatOptions:              []string{"Argentina", "Brazil", "Chile", "Côte d'Ivoire"},
	TwoWayStatePath:          "country",
	ShouldIncludeBlankOption: true,
})
Alpine.js Parent State (x-data)
<div x-data="{country: 'Brazil'}"></div>

Live Example

A select bound to Alpine state, with a blank option and flat option labels.

Country
Country

Value:

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

LabelValueOptions
LabelValueOptions

LabelValueOptions send a stored Value while showing a human Label. The bound state holds the Value.

Usage

@uiForm.SelectInput(uiForm.SelectInputSettings{
	InputName: "countryCode",
	Label:     "Country",

	// OptionalFields
	LabelValueOptions: []uiForm.SelectLabelValueOption{
		{Label: "Argentina", Value: "AR"},
		{Label: "Brazil", Value: "BR"},
		{Label: "Chile", Value: "CL"},
	},
	TwoWayStatePath:          "country",
	ShouldIncludeBlankOption: true,
})
Alpine.js Parent State (x-data)
<div x-data="{country: 'BR'}"></div>
Country
Country
HTML Option Labels
HTML Option Labels

LabelHtml replaces the plain option label with custom markup in the dropdown.

Usage

@uiForm.SelectInput(uiForm.SelectInputSettings{
	InputName: "countryWithHtml",
	Label:     "Country",

	// OptionalFields
	LabelValueOptions: []uiForm.SelectLabelValueOption{
		{Label: "Argentina", LabelHtml: SelectInputDemoOption1(), Value: "AR"},
		{Label: "Brazil", LabelHtml: SelectInputDemoOption2(), Value: "BR"},
		{Label: "Chile", LabelHtml: SelectInputDemoOption3(), Value: "CL"},
	},
	TwoWayStatePath:          "country",
	ShouldIncludeBlankOption: true,
})
Alpine.js Parent State (x-data)
<div x-data="{country: 'BR'}"></div>

Click the dropdown to see the HTML labels.

Country
Country
Hints
Hints

HintValue explains the field. HintDisplay shows it as a description below the field or as a tooltip.

Usage

@uiForm.SelectInput(uiForm.SelectInputSettings{
	InputName: "countryHint",
	Label:     "Country",

	// OptionalFields
	FlatOptions:     []string{"Argentina", "Brazil", "Chile"},
	TwoWayStatePath: "country",
	HintValue:        "This is a helpful hint.",
	HintDisplay:      uiForm.InputHintDisplayDescription,
})
Country
Country
This is a helpful hint displayed as a description below the select.
Country
Country
Hint Icon Styles
Hint Icon Styles

HintIconStyle renders the hint trigger as an icon or as a boxed tooltip.

Usage

@uiForm.SelectInput(uiForm.SelectInputSettings{
	InputName: "countryHintBoxed",
	Label:     "Country",

	// OptionalFields
	FlatOptions:     []string{"Argentina", "Brazil", "Chile"},
	TwoWayStatePath: "country",
	HintValue:        "This is a helpful hint.",
	HintDisplay:      uiForm.InputHintDisplayTooltip,
	HintIconStyle:    uiForm.InputHintIconStyleBoxed,
})
Country
Country
OnChangeFunc
OnChangeFunc

OnChangeFunc runs when the selection changes and when the field is cleared.

Usage

@uiForm.SelectInput(uiForm.SelectInputSettings{
	InputName: "countryChange",
	Label:     "Country",

	// OptionalFields
	FlatOptions:              []string{"Argentina", "Brazil", "Chile"},
	TwoWayStatePath:          "country",
	ShouldIncludeBlankOption: true,
	OnChangeFunc:             "onCountryChange()",
})
Alpine.js Parent State (x-data)
<div x-data="{country: 'Brazil', changeCount: 0, onCountryChange() { this.changeCount++ }}"></div>

The function runs when the selection changes. Clear the field to see it run again.

Country
Country

Change count:

.TextArea

A textarea is a form element that allows users to enter multiple lines of text.

Usage

@uiForm.TextArea(uiForm.TextAreaSettings{
	InputName: "description",
	Label:     "Description",

	// OptionalFields
	TwoWayStatePath: "description",
})
Alpine.js Parent State (x-data)
<div x-data="{description: ''}"></div>

Live Example

A labeled textarea bound to Alpine state.

Description

Value:

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Value & Read-Only
Value & Read-Only

Value seeds the field content. IsReadOnly shows the value without accepting edits.

Usage

@uiForm.TextArea(uiForm.TextAreaSettings{
	InputName: "description",
	Label:     "Description",

	// OptionalFields
	Value:      "Lorem ipsum dolor sit amet.",
	IsReadOnly: true,
})
Description
Code Mode
Code Mode

IsCode switches the field to a monospace editor styled for source code.

Usage

@uiForm.TextArea(uiForm.TextAreaSettings{
	InputName: "snippet",
	Label:     "Snippet",

	// OptionalFields
	TwoWayStatePath: "snippet",
	IsCode:          true,
})
Snippet
Hints
Hints

HintValue explains the field. HintDisplay shows it as a description below the field or as a tooltip.

Usage

@uiForm.TextArea(uiForm.TextAreaSettings{
	InputName: "description",
	Label:     "Description",

	// OptionalFields
	TwoWayStatePath: "description",
	HintValue:       "This is a helpful hint.",
	HintDisplay:     uiForm.InputHintDisplayDescription,
})
Description
This is a helpful hint displayed as a description below the textarea.
Description
Hint State Path
Hint State Path

HintStatePath reads the hint text from Alpine state, so the hint updates as the state changes.

Usage

@uiForm.TextArea(uiForm.TextAreaSettings{
	InputName: "description",
	Label:     "Description",

	// OptionalFields
	TwoWayStatePath: "description",
	HintStatePath:   "hintText",
	HintDisplay:     uiForm.InputHintDisplayTooltip,
})
Description

.ToggleSwitch

A switch toggles a boolean state or adds and removes a custom value from an array.

Usage

@uiForm.ToggleSwitch(uiForm.ToggleSwitchSettings{
	Label:           "Enable notifications",
	TwoWayStatePath: "isNotificationsEnabled",

	// OptionalFields
	InputName: "notificationsEnabled",
})
Alpine.js Parent State (x-data)
<div x-data="{isNotificationsEnabled: false}"></div>
<div x-data="{selectedChannels: ['email']}"></div>

Live Example

The two binding modes: a boolean toggle and channel switches bound to an array.

Boolean state

Value:

Array state

Values:

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Sizes
Sizes

Size scales the track, thumb, and label: xs, sm, md, lg, or xl.

Usage

@uiForm.ToggleSwitch(uiForm.ToggleSwitchSettings{
	Label:           "Enable notifications",
	TwoWayStatePath: "isNotificationsEnabled",

	// OptionalFields
	Size: uiForm.ToggleSwitchSizeMd,
})
Label Position
Label Position

LabelPosition places the label on the left or the right of the switch.

Usage

@uiForm.ToggleSwitch(uiForm.ToggleSwitchSettings{
	Label:           "Enable notifications",
	TwoWayStatePath: "isNotificationsEnabled",

	// OptionalFields
	LabelPosition: uiForm.ToggleSwitchLabelPositionLeft,
})
Color Variants
Color Variants

Track, thumb, and focus colors accept Tailwind color tokens.

Usage

@uiForm.ToggleSwitch(uiForm.ToggleSwitchSettings{
	Label:                       "Emerald accent",
	TwoWayStatePath:             "emeraldEnabled",

	// OptionalFields
	TrackBackgroundColor:        "emerald-900/40",
	TrackCheckedBackgroundColor: "emerald-500",
	FocusRingColor:              "emerald-500/50",
})
Required & Disabled
Required & Disabled

IsRequired marks the switch as required. IsDisabled blocks edits.

Usage

@uiForm.ToggleSwitch(uiForm.ToggleSwitchSettings{
	Label:           "Enable notifications",
	TwoWayStatePath: "isNotificationsEnabled",

	// OptionalFields
	IsRequired: true,
	IsDisabled: false,
})

@uiDisplay

uiDisplay is a collection of components for displaying content.

.Accordion

An accordion is a vertically stacked list of items that can be expanded or collapsed to reveal content.

Usage

@uiDisplay.Accordion(uiDisplay.AccordionSettings{
	Items: []uiDisplay.AccordionItemSettings{
		{Title: "Section 1", Content: AccordionDemoSection1()},
		{Title: "Section 2", Content: AccordionDemoSection2()},
		{Title: "Section 3", Content: AccordionDemoSection3()},
	},
})

Live Example

Three titled sections, each holding its own content.

Section 1

This is the content for section 1. You can put any content here.

Section 2

This is the content for section 2. You can put any content here.

Section 3

This is the content for section 3. You can put any content here.

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Item Icons
Item Icons

Icon renders a Phosphor icon beside the item title.

Usage

@uiDisplay.Accordion(uiDisplay.AccordionSettings{
	Items: []uiDisplay.AccordionItemSettings{
		{Title: "Section 1", Content: AccordionDemoSection1(), Icon: "ph-info"},
		{Title: "Section 2", Content: AccordionDemoSection2(), Icon: "ph-warning"},
	},
})
Section 1

This is the content for section 1. You can put any content here.

Section 2

This is the content for section 2. You can put any content here.

Section 3

This is the content for section 3. You can put any content here.

Surface & Padding
Surface & Padding

Background, open background, content background, title color, border, and radius style the item surface. PaddingSize and ContentPaddingSize scale the paddings.

Usage

@uiDisplay.Accordion(uiDisplay.AccordionSettings{
	Items: []uiDisplay.AccordionItemSettings{
		{Title: "Section 1", Content: AccordionDemoSection1()},
	},

	// OptionalFields
	BackgroundColor:        "primary-900/40",
	OpenBackgroundColor:    "primary-800/60",
	ContentBackgroundColor: "primary-950",
	TitleColor:             "primary-100",
	BorderColor:            "primary-500/30",
	BorderRadius:           uiDisplay.AccordionBorderRadiusXl,
	PaddingSize:            uiDisplay.AccordionPaddingSizeLg,
	ContentPaddingSize:     uiDisplay.AccordionPaddingSizeXl,
})
Section 1

This is the content for section 1. You can put any content here.

Section 2

This is the content for section 2. You can put any content here.

Single Open
Single Open

IsSingleOpen keeps one item open at a time. Opening a section closes the section that was open.

Usage

@uiDisplay.Accordion(uiDisplay.AccordionSettings{
	Items: []uiDisplay.AccordionItemSettings{
		{Title: "Section 1", Content: AccordionDemoSection1()},
		{Title: "Section 2", Content: AccordionDemoSection2()},
		{Title: "Section 3", Content: AccordionDemoSection3()},
	},

	// OptionalFields
	IsSingleOpen: true,
})
Section 1

This is the content for section 1. You can put any content here.

Section 2

This is the content for section 2. You can put any content here.

Section 3

This is the content for section 3. You can put any content here.

Text Case
Text Case

TextCase transforms the item titles. It accepts uiToolset.TextCaseNone (the default, as typed), TextCaseLower, TextCaseUpper, or TextCaseCapitalize.

Usage

@uiDisplay.Accordion(uiDisplay.AccordionSettings{
	Items: []uiDisplay.AccordionItemSettings{
		{Title: "Section 1", Content: AccordionDemoSection1()},
		{Title: "Section 2", Content: AccordionDemoSection2()},
	},

	// OptionalFields
	TextCase: uiToolset.TextCaseUpper,
})
Section 1

This is the content for section 1. You can put any content here.

Section 2

This is the content for section 2. You can put any content here.

.Alert

An alert is a notification component that displays important information to users.

Usage

@uiDisplay.Alert(uiDisplay.AlertSettings{
	Title:       "Alert Title",
	Description: "This is an alert message.",
	Variation:   uiDisplay.AlertVariationInfo,
	Size:        uiDisplay.AlertSizeMd,
	IsCloseable: true,
})

Live Example

The four tone variations: success, warning, error, and info.

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Sizes
Sizes

Size scales the alert padding and type: xs, sm, md, lg, or xl.

Usage

@uiDisplay.Alert(uiDisplay.AlertSettings{
	Title:       "Alert Title",
	Description: "This is an alert message.",
	Variation:   uiDisplay.AlertVariationInfo,
	Size:        uiDisplay.AlertSizeMd,
})
Content Html Slot
Content Html Slot

ContentHtml replaces the plain description with a templ component of your own.

Usage

@uiDisplay.Alert(uiDisplay.AlertSettings{
	Title: "Deploy finished",

	// OptionalFields
	ContentHtml: AlertDemoCustomContent(),
})
Close & Timeout
Close & Timeout

IsCloseable adds the dismiss button and OnCloseFunc runs when it is pressed. DisplayTimeoutSeconds auto-dismisses the alert and runs OnTimeoutFunc.

Usage

@uiDisplay.Alert(uiDisplay.AlertSettings{
	Title:       "Alert Title",
	Description: "This is an alert message.",

	// OptionalFields
	IsCloseable:           true,
	OnCloseFunc:           "alertClosed = true",
	DisplayTimeoutSeconds: 8,
	OnTimeoutFunc:         "alertTimedOut = true",
})

Closed: · Timed out:

Custom Surface
Custom Surface

Background, text, ring, radius, shadow, and close-icon colors accept Tailwind tokens. Gradient backgrounds work too.

Usage

@uiDisplay.Alert(uiDisplay.AlertSettings{
	Title:       "Alert Title",
	Description: "This is an alert message.",

	// OptionalFields
	BackgroundColor:          "cyan-500/20",
	TextColor:                "cyan-100",
	RingThickness:            uiDisplay.AlertRingThicknessLg,
	RingColor:                "cyan-400",
	ShadowSize:               uiDisplay.AlertShadowSizeXl,
	CloseIconBackgroundColor: "cyan-500/30",
})
State-Bound Content
State-Bound Content

DescriptionOneWayStatePath and IsCloseableOneWayStatePath drive the alert from Alpine state.

Usage

@uiDisplay.Alert(uiDisplay.AlertSettings{
	Title:                      "Dynamic Content Alert",
	DescriptionOneWayStatePath: "alertMessage",
	Variation:                  uiDisplay.AlertVariationInfo,

	// OptionalFields
	IsCloseableOneWayStatePath: "isAlertCloseable",
})

.CloakLoading (pre-Alpine/HTMX)

A cloak loading screen that appears only before the JavaScript libraries are loaded to prevent FOUC (Flash of Unstyled Content).

Usage

@uiDisplay.CloakLoading(uiDisplay.CloakLoadingSettings{
	// OptionalFields
	BackgroundColor: "rgb(23, 23, 23)",
	Icon:            "ph-compass-rose",
})
Set colors as rgb(a), hex, or hsl(a) values: they are used in the inline style.

Live Example

Since the demo is already loaded with Alpine.js, the CloakLoading component will behave like a regular loading overlay. In a real application, this would be the first thing that appears when the page starts loading.

The page content will be covered by the cloak loading screen when triggered.

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Custom Text
Custom Text

TextMessage replaces the default loading label. TextColor and TextSize style it. Set colors as rgb(a), hex, or hsl(a) values: they are used in an inline style.

Usage

@uiDisplay.CloakLoading(uiDisplay.CloakLoadingSettings{
	// OptionalFields
	BackgroundColor: "rgb(30, 58, 138)",
	TextMessage:     "Please wait...",
	TextColor:       "rgb(255, 255, 255)",
	TextSize:        uiDisplay.CloakLoadingTextSizeLg,
})

The cloak screen covers this content when triggered.

Icon & Animation
Icon & Animation

Icon replaces the spinner. IconSize scales it. IconAnimationName spins or pulses it over IconAnimationDurationSeconds.

Usage

@uiDisplay.CloakLoading(uiDisplay.CloakLoadingSettings{
	// OptionalFields
	Icon:                         "ph-hourglass",
	IconSize:                     uiDisplay.CloakLoadingIconSizeMd,
	IconColor:                    "rgb(110, 231, 183)",
	IconAnimationName:            uiDisplay.CloakLoadingAnimationNamePulse,
	IconAnimationDurationSeconds: "2",
})

The cloak screen covers this content when triggered.

Hide Delay
Hide Delay

HideDelaySeconds keeps the cloak on screen for a moment after the libraries load, so the hand-off does not flash. It defaults to 0 seconds.

Usage

@uiDisplay.CloakLoading(uiDisplay.CloakLoadingSettings{
	// OptionalFields
	HideDelaySeconds: "3",
})

The cloak screen covers this content when triggered.

.ConfirmationDialog

Confirmation dialog presets: confirm, warning, critical, and delete. Each preset supplies its icon, tone, and confirmation copy. Delete and critical gate the confirm action behind typing the target name.

Usage

@uiDisplay.DeleteDialog(uiDisplay.ConfirmationDialogSettings{
	IsVisibleTwoWayStatePath: "isDeleteDialogVisible",
	OnConfirmFunc:            "deleteRecord()",

	// OptionalFields
	TargetNameStatePath: "demoTargetName",
	TargetIdStatePath:   "demoTargetId",
})
Alpine.js Parent State (x-data)
<div x-data="{
  isDeleteDialogVisible: false,
  demoTargetName: 'primary-database',
  demoTargetId: '42',
}"></div>

Live Example

The four presets against one target. Delete and critical require typing the target name.

Target: (id: ) · Confirmed: nothing yet

Presets

Confirm Action

Are you sure you want to proceed with # ?

This action needs your confirmation.

Warning

Are you sure you want to proceed with # ?

Review the effects before you continue.

Critical Action

Are you sure you want to proceed with # ?

This action cannot be undone.

Type the name to confirm

Delete

Are you sure you want to delete # ?

This process cannot be undone. This will permanently delete the element(s).

Type the name to confirm

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Type-to-Confirm
Type-to-Confirm

IsTypeToConfirmEnabled gates the confirm button behind a typed match. The match comes from TargetNameStatePath, TargetIdStatePath, or TypeToConfirmExpectedValue. The delete and critical presets enable this by default.

Usage

@uiDisplay.ConfirmDialog(uiDisplay.ConfirmationDialogSettings{
	IsVisibleTwoWayStatePath: "isTypeToConfirmVisible",
	OnConfirmFunc:            "runAction()",

	// OptionalFields
	IsTypeToConfirmEnabled:     true,
	TypeToConfirmExpectedValue: "proceed",
})

Confirmed:

Typed Prompt

Are you sure you want to proceed?

This action needs your confirmation.

Type "proceed" to confirm
Uncloseable
Uncloseable

IsUncloseable hides the close button and ignores backdrop clicks. CancelFunc still closes the dialog from its cancel button.

Usage

@uiDisplay.ConfirmDialog(uiDisplay.ConfirmationDialogSettings{
	IsVisibleTwoWayStatePath: "isUncloseableVisible",
	OnConfirmFunc:            "runAction()",

	// OptionalFields
	IsUncloseable: true,
	CancelFunc:    "isUncloseableVisible = false",
})

Uncloseable Prompt

Are you sure you want to proceed?

This action needs your confirmation.

Button Labels & Icons
Button Labels & Icons

ConfirmButtonLabel, ConfirmButtonIcon, and CancelButtonLabel override the preset copy. CancelFunc runs when the cancel button is pressed.

Usage

@uiDisplay.ConfirmDialog(uiDisplay.ConfirmationDialogSettings{
	IsVisibleTwoWayStatePath: "isLabelsVisible",
	OnConfirmFunc:            "runAction()",

	// OptionalFields
	HeaderTitle:        "Purge Records",
	ConfirmButtonLabel: "Purge Everything",
	ConfirmButtonIcon:  "ph-fire",
	CancelButtonLabel:  "Keep It",
})

Confirmed:

Purge Records

Are you sure you want to proceed?

This action needs your confirmation.

Custom Message & Header
Custom Message & Header

MessageContent replaces the question copy. HeaderContent replaces the icon and title block. Size sets the dialog width.

Usage

@uiDisplay.ConfirmDialog(uiDisplay.ConfirmationDialogSettings{
	IsVisibleTwoWayStatePath: "isSlotsVisible",
	OnConfirmFunc:            "runAction()",

	// OptionalFields
	MessageContent: ConfirmationDialogDemoCustomMessage(),
	HeaderContent:  ConfirmationDialogDemoCustomHeader(),
	Size:           uiDisplay.ConfirmationDialogSizeLg,
})

Confirmed:

Maintenance window

Drain the edge pool?

Billing impact

Removing this record stops the metered plan at the end of the cycle. Invoices already issued stay open.

Icon On Left
Icon On Left

HeaderIconPosition defaults to Top, which centers the icon above the title. HeaderIconPositionLeft places it beside the title.

Usage

@uiDisplay.WarningDialog(uiDisplay.ConfirmationDialogSettings{
	IsVisibleTwoWayStatePath: "isIconPositionVisible",
	OnConfirmFunc:            "runAction()",

	// OptionalFields
	HeaderIconPosition: uiDisplay.HeaderIconPositionLeft,
})

Icon Beside Title

Are you sure you want to proceed?

Review the effects before you continue.

.LoadingOverlay (htmx-ready)

A loading overlay displays a loading indicator over content to show that an operation is in progress.

Usage

@uiDisplay.LoadingOverlay(uiDisplay.LoadingOverlaySettings{
	IsLoadingOneWayStatePath: "isLoading",
})
Alpine.js Parent State (x-data)
<div x-data="{isLoading: false}"></div>

Live Example

An overlay driven by one boolean state path. Trigger it to cover the content below.

The page content will be covered by the loading overlay when triggered.

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Icon & Animation
Icon & Animation

Icon replaces the spinner. IconSize scales it. AnimationName spins or pulses it over AnimationDurationSeconds.

Usage

@uiDisplay.LoadingOverlay(uiDisplay.LoadingOverlaySettings{
	IsLoadingOneWayStatePath: "isLoading",

	// OptionalFields
	Icon:                     "ph-compass-rose",
	IconSize:                 uiDisplay.LoadingOverlayIconSizeMd,
	AnimationName:            uiDisplay.LoadingOverlayAnimationNameSpin,
	AnimationDurationSeconds: "2",
})

The overlay covers this content while it loads.

Background Color
Background Color

BackgroundColor paints the veil over the content.

Usage

@uiDisplay.LoadingOverlay(uiDisplay.LoadingOverlaySettings{
	IsLoadingOneWayStatePath: "isLoading",

	// OptionalFields
	BackgroundColor: "neutral-900/80",
})

The overlay covers this content while it loads.

.Tag

A tag is a small label that can be used to categorize or identify content.

Usage

@uiDisplay.Tag(uiDisplay.TagSettings{
	OuterLeftIcon:  "ph-info",
	OuterLeftLabel: "Info",
	InnerLabel:     "Warning",
})

Live Example

The common shapes: an outer label with an inner label, and an outer label with a bound inner value.

Info
Warning
count

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Sizes
Sizes

Size scales the outer and inner segments: tiny, xs, sm, md, lg, or xl.

Usage

@uiDisplay.Tag(uiDisplay.TagSettings{
	OuterLeftIcon:  "ph-info",
	OuterLeftLabel: "Info",
	InnerIcon:      "ph-warning",
	InnerLabel:     "Warning",

	// OptionalFields
	Size: uiDisplay.TagSizeSm,
})
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Radii
Radii

OuterRadius rounds the outer segment and InnerRadius rounds the inner one: none, xs, sm, md, lg, xl, or full.

Usage

@uiDisplay.Tag(uiDisplay.TagSettings{
	OuterLeftIcon:  "ph-info",
	OuterLeftLabel: "Info",
	InnerIcon:      "ph-warning",
	InnerLabel:     "Warning",

	// OptionalFields
	OuterRadius: uiDisplay.TagRadiusMd,
	InnerRadius: uiDisplay.TagRadiusMd,
})
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Outer Ring Colors
Outer Ring Colors

OuterRingColor outlines the outer segment. Pair it with a transparent OuterBackgroundColor for an outlined tag.

Usage

@uiDisplay.Tag(uiDisplay.TagSettings{
	OuterLeftIcon:  "ph-info",
	OuterLeftLabel: "Info",

	// OptionalFields
	OuterRingColor:       "emerald-500",
	OuterBackgroundColor: "transparent",
	OuterTextColor:       "neutral-50",
})
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Outer Background Colors
Outer Background Colors

OuterBackgroundColor fills the outer segment. OuterTextColor paints its label and icon.

Usage

@uiDisplay.Tag(uiDisplay.TagSettings{
	OuterLeftIcon:  "ph-info",
	OuterLeftLabel: "Info",

	// OptionalFields
	OuterBackgroundColor: "emerald-500",
	OuterTextColor:       "neutral-50",
})
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Inner Colors
Inner Colors

InnerBackgroundColor and InnerTextColor style the inner segment only.

Usage

@uiDisplay.Tag(uiDisplay.TagSettings{
	OuterLeftIcon:  "ph-info",
	OuterLeftLabel: "Info",
	InnerIcon:      "ph-warning",
	InnerLabel:     "Warning",

	// OptionalFields
	InnerBackgroundColor: "emerald-500",
	InnerTextColor:       "neutral-50",
})
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Side Element Actions
Side Element Actions

OuterLeftOnClickFunc and OuterRightOnClickFunc run on the outer side labels. InnerLabelOneWayStatePath and InnerValueOneWayStatePath mirror Alpine state into the inner segment.

Usage

@uiDisplay.Tag(uiDisplay.TagSettings{
	OuterLeftIcon:             "ph-plus",
	OuterLeftLabel:            "Add",
	OuterLeftOnClickFunc:      "clickCount++",
	OuterRightIcon:            "ph-minus",
	OuterRightLabel:           "Remove",
	OuterRightOnClickFunc:     "if(clickCount > 0) clickCount--",
	InnerIcon:                 "ph-hash",
	InnerLabelOneWayStatePath: "clickCount",
})
Add
Remove
count

Count:

Removable Tags
Removable Tags

OnRemoveFunc renders a remove button on the tag. RemoveButtonLabel names it for screen readers.

Usage

@uiDisplay.Tag(uiDisplay.TagSettings{
	OuterLeftLabel: "Status: running",

	// OptionalFields
	OnRemoveFunc:         "showTag = false",
	RemoveButtonLabel:    "Remove status filter",
})
Status: running
Text Case
Text Case

TextCase transforms the tag labels. It accepts uiToolset.TextCaseNone (the default, as typed), TextCaseLower, TextCaseUpper, or TextCaseCapitalize.

Usage

@uiDisplay.Tag(uiDisplay.TagSettings{
	OuterLeftLabel: "Info",
	InnerLabel:     "Warning",

	// OptionalFields
	TextCase: uiToolset.TextCaseUpper,
})
Info (none)
Warning
Info (lower)
Warning
Info (upper)
Warning
Info (capitalize)
Warning

.Toast

A toast is a temporary notification displayed to provide feedback to users.

Usage

@uiDisplay.Toast(uiDisplay.ToastSettings{
	// OptionalFields
	AutoDismissSeconds: 6,
	BackgroundColor:    "neutral-800",
	TextColor:          "neutral-50",
	Size:               uiDisplay.ToastSizeMd,
	RingThickness:      uiDisplay.ToastRingThicknessMd,
	RingColor:          "neutral-500",
	Radius:             uiDisplay.ToastRadiusMd,
})
@uiControl.Button(uiControl.ButtonSettings{
	OnClickFunc: "$store.toast.displayToast('Saved!', 'success')",
})

Live Example

One toast mount serves every message. Trigger the success, warning, and error tones below.

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

API Response Toasts
API Response Toasts

displayToastWithApiResponse reads an Infinite API envelope and picks the tone from the status code: 207 is a partial success, 400 and above is an error, anything else is a success.

Usage

$store.toast.displayToastWithApiResponse(apiResponse, httpStatusCode)
$store.toast.displayToastWithApiResponse({readableMessage: "Server rebuilt"}, 200)
Mount Settings
Mount Settings

AutoDismissSeconds sets how long each toast stays up; it defaults to 10 seconds. Background, text, ring, and radius accept Tailwind tokens. Mount one Toast per page: the mount configures the shared toast store.

Usage

@uiDisplay.Toast(uiDisplay.ToastSettings{
	// OptionalFields
	AutoDismissSeconds: 6,
	BackgroundColor:    "neutral-800",
	TextColor:          "neutral-50",
	Size:               uiDisplay.ToastSizeMd,
	RingThickness:      uiDisplay.ToastRingThicknessMd,
	RingColor:          "neutral-500",
	Radius:             uiDisplay.ToastRadiusMd,
})

The live example above already mounts a styled toast with a 6 second auto-dismiss. Every button on this page uses that mount.

@uiControl

uiControl is a collection of components for controlling content.

.Button

A button is a clickable element that can be used to trigger an action.

Usage

@uiControl.Button(uiControl.ButtonSettings{
	Label:       "Click me",
	IconLeft:    "ph-info",
	OnClickFunc: "alert('Button clicked!')",
})

Live Example

The action buttons an app reaches for: a primary action, a quiet secondary, and a destructive one.

New Record clicks:

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Sizes
Sizes

Size scales the button and its type: xs, sm, md, lg, or xl.

Usage

@uiControl.Button(uiControl.ButtonSettings{
	Label: "Button",

	// OptionalFields
	Size: uiControl.ButtonSizeMd,
})
Shapes
Shapes

Shape rounds the button frame: square, rounded, or circular.

Usage

@uiControl.Button(uiControl.ButtonSettings{
	Label: "Button",

	// OptionalFields
	Shape: uiControl.ButtonShapeRounded,
})
Icons
Icons

IconLeft and IconRight flank the label with Phosphor icons.

Usage

@uiControl.Button(uiControl.ButtonSettings{
	Label: "Info",

	// OptionalFields
	IconLeft:  "ph-info",
	IconRight: "ph-arrow-right",
})
Colors
Colors

Background and text colors accept Tailwind tokens. The Hover variants paint the hover state.

Usage

@uiControl.Button(uiControl.ButtonSettings{
	Label: "Save",

	// OptionalFields
	BackgroundColor:      "emerald-500",
	BackgroundColorHover: "emerald-600",
	TextColor:            "neutral-50",
	TextColorHover:       "neutral-50",
})
Rings
Rings

RingColor and RingThickness outline the button. The Hover variants paint the hover ring.

Usage

@uiControl.Button(uiControl.ButtonSettings{
	Label: "Red Ring",

	// OptionalFields
	BackgroundColor:      "red-500/10",
	BackgroundColorHover: "red-500/20",
	RingColor:            "red-500",
	RingColorHover:       "red-400",
	RingThickness:        uiControl.ButtonRingThicknessMd,
})
Tooltips
Tooltips

TooltipContent renders a tooltip on hover. TooltipPosition places it on any side. TooltipContentHtml accepts a component, and TooltipContentOneWayStatePath binds live text.

Usage

@uiControl.Button(uiControl.ButtonSettings{
	Label: "Top Tooltip",

	// OptionalFields
	TooltipContent:  "This tooltip appears on top",
	TooltipPosition: uiControl.ButtonTooltipPositionTop,
})
Disabled Binding
Disabled Binding

IsDisabledOneWayStatePath disables the button from Alpine state. IsDisabled disables it outright.

Usage

@uiControl.Button(uiControl.ButtonSettings{
	Label: "Click Me",

	// OptionalFields
	OnClickFunc:               "clickCount++",
	IsDisabledOneWayStatePath: "shouldDisable",
})

Count:

Full-Width & Submit
Full-Width & Submit

IsFullWidth stretches the button to its container. IsSubmit renders a submit input for forms.

Usage

@uiControl.Button(uiControl.ButtonSettings{
	Label: "Save",

	// OptionalFields
	IsFullWidth: true,
	IsSubmit:    true,
})
Text Case
Text Case

TextCase transforms the button label. It accepts uiToolset.TextCaseNone (the default, as typed), TextCaseLower, TextCaseUpper, or TextCaseCapitalize.

Usage

@uiControl.Button(uiControl.ButtonSettings{
	Label:    "New Record",
	TextCase: uiToolset.TextCaseUpper,
})

.RangeSlider

A range slider allows users to select a value from a range by dragging a thumb along a track.

Usage

@uiControl.RangeSlider(uiControl.RangeSliderSettings{
	ThumbValueTwoWayStatePath: "sliderValue",

	// OptionalFields
	TrackStartValue: "0",
	TrackEndValue:   "100",
})
Alpine.js Parent State (x-data)
<div x-data="{sliderValue: 50}"></div>

Live Example

A slider bound to one numeric Alpine state path. Drag the thumb or use the arrow keys.

Value:

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Sizes
Sizes

Size scales the track, thumb, and labels: xs, sm, md, lg, or xl.

Usage

@uiControl.RangeSlider(uiControl.RangeSliderSettings{
	ThumbValueTwoWayStatePath: "sliderValue",

	// OptionalFields
	Size: uiControl.RangeSliderSizeMd,
})
Thumb Shapes
Thumb Shapes

ThumbShape draws the thumb as circular, rounded, square, or pipe.

Usage

@uiControl.RangeSlider(uiControl.RangeSliderSettings{
	ThumbValueTwoWayStatePath: "sliderValue",

	// OptionalFields
	ThumbShape: uiControl.RangeSliderThumbShapeCircular,
})
Thumb Colors & Icons
Thumb Colors & Icons

Thumb background and text colors accept Tailwind tokens. ThumbLabelIcon stamps an icon on the thumb and ThumbLabelOneWayStatePath prints live state on it.

Usage

@uiControl.RangeSlider(uiControl.RangeSliderSettings{
	ThumbValueTwoWayStatePath: "sliderValue",

	// OptionalFields
	ThumbBackgroundColor:      "emerald-500",
	ThumbTextColor:            "neutral-50",
	ThumbLabelIcon:            "ph-check",
	ThumbLabelOneWayStatePath: "sliderValue",
})
Value Bubble
Value Bubble

ThumbValueBubbleEnabled shows the live value above or below the thumb. Bubble colors, size, shape, ring, and position style it.

Usage

@uiControl.RangeSlider(uiControl.RangeSliderSettings{
	ThumbValueTwoWayStatePath: "sliderValue",

	// OptionalFields
	ThumbValueBubbleEnabled:         true,
	ThumbValueBubblePosition:        uiControl.RangeSliderThumbValueBubblePositionTop,
	ThumbValueBubbleBackgroundColor: "red-500",
	ThumbValueBubbleTextColor:       "neutral-50",
})
Track Labels
Track Labels

Track start and end labels print the range bounds. Their position moves them above or below the track.

Usage

@uiControl.RangeSlider(uiControl.RangeSliderSettings{
	ThumbValueTwoWayStatePath: "sliderValue",
	TrackStartValue:           "0",
	TrackEndValue:             "100",

	// OptionalFields
	TrackStartValueLabelEnabled:  true,
	TrackStartValueLabelPosition: uiControl.RangeSliderTrackValueLabelPositionTop,
	TrackEndValueLabelEnabled:    true,
	TrackEndValueLabelPosition:   uiControl.RangeSliderTrackValueLabelPositionTop,
})
Track Colors & Icons
Track Colors & Icons

Track background colors paint a solid or gradient track. Label text colors and icons mark the bounds.

Usage

@uiControl.RangeSlider(uiControl.RangeSliderSettings{
	ThumbValueTwoWayStatePath: "sliderValue",
	TrackStartValue:           "0",
	TrackEndValue:             "100",

	// OptionalFields
	TrackBackgroundColorFrom:      "red-500",
	TrackBackgroundColorVia:       "emerald-500",
	TrackBackgroundColorTo:        "cyan-500",
	TrackStartValueLabelTextColor: "red-500",
	TrackEndValueLabelTextColor:   "cyan-500",
})
Steps & Ticks
Steps & Ticks

TrackSteps snaps the thumb to increments. TrackTicksEnabled draws tick marks every TrackTickStep.

Usage

@uiControl.RangeSlider(uiControl.RangeSliderSettings{
	ThumbValueTwoWayStatePath: "sliderValue",

	// OptionalFields
	TrackSteps:       "20",
	TrackTicksEnabled: true,
	TrackTickStep:     "25",
})
Dual-Thumb Mode
Dual-Thumb Mode

ThumbDualValueModeEnabled turns the slider into a range picker. Each thumb binds its own state path and aria label.

Usage

@uiControl.RangeSlider(uiControl.RangeSliderSettings{
	ThumbDualValueModeEnabled:      true,
	ThumbValueTwoWayStatePath:      "lowerValue",
	ThumbAriaLabel:                 "Minimum price",
	ThumbUpperValueTwoWayStatePath: "upperValue",
	ThumbUpperAriaLabel:            "Maximum price",
	ThumbValueBubbleEnabled:        true,
	ThumbUpperValueBubbleEnabled:   true,
	TrackStartValue:                "0",
	TrackEndValue:                  "100",
})

Price Range: $ - $

Initial State Normalization
Initial State Normalization

ShouldNormalizeInitialState orders crossed thumbs and pulls out-of-range values back into the track on load. Without it the thumbs start where the state says.

Usage

@uiControl.RangeSlider(uiControl.RangeSliderSettings{
	ThumbDualValueModeEnabled:      true,
	ThumbValueTwoWayStatePath:      "lowerValue",
	ThumbUpperValueTwoWayStatePath: "upperValue",

	// OptionalFields
	ShouldNormalizeInitialState: true,
	TrackStartValue:             "0",
	TrackEndValue:               "100",
})

Normalized Range: $ - $, Overflow Range: $ - $, Slider:

Raw Range: $ - $

@uiStructural

uiStructural is a collection of components for navigating and displaying structured data.

.Card

A card is a surface container with an optional page-style heading (header title, icon, sub-heading) and customizable edges, shadow, ring, and padding.

Usage

@uiStructural.Card(uiStructural.CardSettings{
	MiddleContent: CardDemoBody(),

	// OptionalFields
	HeaderTitle:      "Card Title",
	HeaderSubHeading: "Card sub-heading",
	HeaderIcon:       "ph-cube",
})

Live Example

The complete card: header with icon and sub-heading, a body, and a footer with actions.

Default Card

Rounded edges and an icon heading

Cards group related content on a surface. This body is the MiddleContent, so the card only styles the container and the optional heading.

Card footer content sits below the body.

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Surface & Edges
Surface & Edges

Background, text, radius, shadow, ring, and padding accept Tailwind tokens.

Usage

@uiStructural.Card(uiStructural.CardSettings{
	MiddleContent: CardDemoBody(),

	// OptionalFields
	BackgroundColor: "primary-900/60",
	TextColor:       "neutral-50",
	PaddingSize:     uiStructural.CardPaddingSizeLg,
	BorderRadius:    uiStructural.CardBorderRadiusNone,
	ShadowSize:      uiStructural.CardShadowSizeLg,
	RingColor:       "primary-500",
	RingThickness:   uiStructural.CardRingThicknessMd,
})

Tinted Card

Custom background, text, and ring

Cards group related content on a surface. This body is the MiddleContent, so the card only styles the container and the optional heading.

Square Card

Cards group related content on a surface. This body is the MiddleContent, so the card only styles the container and the optional heading.

Header Icon Styles
Header Icon Styles

HeaderIcon stamps a Phosphor icon in the header. Position, color, background, radius, and padding size style it.

Usage

@uiStructural.Card(uiStructural.CardSettings{
	MiddleContent: CardDemoBody(),

	// OptionalFields
	HeaderIcon:                "ph-cube",
	HeaderIconPosition:        uiDisplay.HeaderIconPositionLeft,
	HeaderIconColor:           "primary-100",
	HeaderIconBackgroundColor: "primary-500/30",
	HeaderIconBorderRadius:    uiDisplay.HeaderIconBorderRadiusLg,
	HeaderIconPaddingSize:     uiDisplay.HeaderIconPaddingSizeMd,
})

Icon on Top

Cards group related content on a surface. This body is the MiddleContent, so the card only styles the container and the optional heading.

Icon on Left

Cards group related content on a surface. This body is the MiddleContent, so the card only styles the container and the optional heading.

Content Gap
Content Gap

GapSize sets the space between the header, body, and footer. The default CardGapSizeMd renders gap-3.

Usage

@uiStructural.Card(uiStructural.CardSettings{
	MiddleContent: CardDemoBody(),
	FooterContent: CardDemoFooter(),

	// OptionalFields
	HeaderTitle: "Tight Gap",
	GapSize:     uiStructural.CardGapSizeSm,
})

Tight Gap

Cards group related content on a surface. This body is the MiddleContent, so the card only styles the container and the optional heading.

Card footer content sits below the body.

Loose Gap

Cards group related content on a surface. This body is the MiddleContent, so the card only styles the container and the optional heading.

Card footer content sits below the body.

Content-Only Card
Content-Only Card

With no header settings the card is a bare surface around MiddleContent.

Usage

@uiStructural.Card(uiStructural.CardSettings{
	MiddleContent: CardDemoContentOnlyBody(),
})

Content-only card body without a heading block above it.

State-Bound Header
State-Bound Header

HeaderTitleOneWayStatePath and HeaderSubHeadingOneWayStatePath drive the header text from Alpine state.

Usage

@uiStructural.Card(uiStructural.CardSettings{
	MiddleContent: CardDemoBody(),

	// OptionalFields
	HeaderTitle:                      "Card Title",
	HeaderTitleOneWayStatePath:       "cardTitle",
	HeaderSubHeadingOneWayStatePath:  "cardSubHeading",
})

Live Title

Cards group related content on a surface. This body is the MiddleContent, so the card only styles the container and the optional heading.

.DataTable

A data table renders rows from column definitions with sorting, selection, filters, search, and pagination. Every change refreshes the table from the server through the URL template. The examples below cover the full settings surface.

Usage

@uiStructural.DataTable(uiStructural.DataTableSettings[Record]{
	Columns:          columns,
	Rows:             records,
	QueryUrlTemplate: "/records?page={pageNumber}&sort={sortKey}&direction={sortDirection}&search={search}",

	// OptionalFields
	Filters:              filters,
	RowIdResolver:        func(record Record) string { return record.Id },
	RefreshOnEvents:      []string{"refresh:records-table"},
	InitialSortKey:       "name",
	InitialSortDirection: uiStructural.DataTableSortDirectionAsc,
})

Live Example

The complete server-driven table: filters, search, sorting, selection, bulk and header actions, and pagination.

Name
Status
Status
CPU min
CPU max
Name:
Status:
CPU:
Search

Status
alpharunning22026-09-01
bravorunning42026-09-02
charliestopped12026-09-03
deltarunning82026-09-04
echorunning22026-09-05

Advanced Examples

The panels below hold static tables. They send no requests, so you can inspect the layout and the configuration without a server. Open a panel to see the settings and the rendered result.

Column Configuration
Column Configuration

A column sets its alignment, width, and sortability. WidthPercent shares the row width, MaxWidthClass caps a long cell, and MinWidthClass holds a floor. A column with a SortKey renders a sort button; one without renders plain text.

Usage

@uiStructural.DataTable(uiStructural.DataTableSettings[Record]{
	Columns: []uiStructural.DataTableColumnSettings[Record]{
		{Label: "Name", SortKey: "name", WidthPercent: 20, CellRenderer: nameCell},
		{Label: "Description", MaxWidthClass: "max-w-72 truncate", CellRenderer: descriptionCell},
		{Label: "Status", Alignment: uiStructural.DataTableAlignmentCenter, WidthPercent: 15, CellRenderer: statusCell},
		{Label: "CPU cores", SortKey: "cpuCores", Alignment: uiStructural.DataTableAlignmentRight, WidthPercent: 12, CellRenderer: cpuCell},
		{Label: "Created at", MinWidthClass: "min-w-28", CellRenderer: createdAtCell},
	},
	Rows: records,
})

Description Status Created at
alphaHandles the public API traffic for the primary region and drains connections during rolling deploys.running22026-09-01
bravoRuns the nightly batch jobs, the reporting pipeline, and the weekly archive export.running42026-09-02
charlieHosts the internal dashboard, the metrics collector, and the alerting rules engine.stopped12026-09-03
deltaServes the static assets, the image resizing service, and the signed download links.running82026-09-04
Rows Configuration
Rows Configuration

RowIdResolver adds the selection column and identifies each row. RowLabelResolver names the row checkbox for screen readers. CheckboxShape, CheckboxSize, and CheckboxCheckedColor change the selection checkbox. Select a row to see the emerald checkbox and the selection count.

Usage

@uiStructural.DataTable(uiStructural.DataTableSettings[Record]{
	Columns:              columns,
	Rows:                 records,
	RowIdResolver:        func(record Record) string { return record.Id },
	RowLabelResolver:     func(record Record) string { return record.Name },
	CheckboxShape:        uiForm.CheckboxInputShapeRounded,
	CheckboxSize:         uiForm.CheckboxInputSizeSm,
	CheckboxCheckedColor: "emerald-500",
})

Name Status CPU cores
alpharunning2
bravorunning4
charliestopped1
deltarunning8
Filters
Filters

Each filter renders an editor and an active chip. InitialFilterValues seeds the starting values. A filter change updates the chips and the filter values.

Usage

@uiStructural.DataTable(uiStructural.DataTableSettings[Record]{
	Columns:             columns,
	Rows:                records,
	Filters:             filters,
	InitialFilterValues: map[string]any{"status": "running"},
})
Name
Status
Status
CPU min
CPU max
Name:
Status:
CPU:

Name Status CPU cores
alpharunning2
bravorunning4
charliestopped1
deltarunning8
echorunning2
Search Box
Search Box

The table renders a default search box when the query template carries the search placeholder. InitialSearchQuery seeds the starting text. SearchBoxAlignment places the box left, center, or right. Pass SearchBox to replace the default box.

Usage

@uiStructural.DataTable(uiStructural.DataTableSettings[Record]{
	Columns:          columns,
	Rows:             records,
	QueryUrlTemplate: "/records?search={search}",

	// OptionalFields
	InitialSearchQuery: "alpha",
	SearchBoxAlignment: uiStructural.DataTableAlignmentCenter,
})
Header Actions
Header Actions

HeaderActions renders in the toolbar. The button here dispatches an event the panel counts.

Usage

@uiStructural.DataTable(uiStructural.DataTableSettings[Record]{
	Columns: columns,
	Rows:    records,
	HeaderActions: uiControl.Button(uiControl.ButtonSettings{
		Label:       "Sync",
		IconLeft:    "ph-arrows-clockwise",
		OnClickFunc: "$dispatch('demo:header-action')",
		Size:        uiControl.ButtonSizeSm,
	}),
})

Name Status CPU cores
alpharunning2
bravorunning4
charliestopped1
deltarunning8

Header action clicks:

Bulk Actions
Bulk Actions

BulkActions renders in the toolbar only while at least one row is selected. Select a row to reveal the action.

Usage

@uiStructural.DataTable(uiStructural.DataTableSettings[Record]{
	Columns: columns,
	Rows:    records,
	RowIdResolver: func(record Record) string { return record.Id },
	BulkActions: uiControl.Button(uiControl.ButtonSettings{
		Label:           "Archive",
		IconLeft:        "ph-archive",
		OnClickFunc:     "selectedRowIds = []",
		Size:            uiControl.ButtonSizeSm,
		BackgroundColor: "red-500/20",
		TextColor:       "red-200",
	}),
})

Name Status CPU cores
alpharunning2
bravorunning4
charliestopped1
deltarunning8
Row and Column Styling
Row and Column Styling

HeaderClass paints the header row. IsStriped adds a zebra stripe. CellClass styles one column, and RowClassResolver styles each row from its data. A cell component that sets its own color overrides the row color.

Usage

@uiStructural.DataTable(uiStructural.DataTableSettings[Record]{
	Columns: []uiStructural.DataTableColumnSettings[Record]{
		{Label: "Name", CellClass: "font-bold", CellRenderer: nameCell},
		{Label: "Status", CellRenderer: statusCell},
		{Label: "CPU cores", Alignment: uiStructural.DataTableAlignmentRight, CellRenderer: cpuCell},
	},
	Rows: records,

	// OptionalFields
	HeaderClass: "bg-neutral-50/5",
	IsStriped:   true,
	RowClassResolver: func(record Record) string {
		if record.Status != "running" {
			return "text-neutral-400"
		}
		return ""
	},
})

Name Status CPU cores
alpharunning2
bravorunning4
charliestopped1
deltarunning8
Density and Header Text Case
Density and Header Text Case

Density changes the cell padding. TextCase changes the header capitalization. Both tables use the same columns and rows. The last column holds an icon button with a tooltip.

Usage

@uiStructural.DataTable(uiStructural.DataTableSettings[Record]{
	Columns:  columns,
	Rows:     records,
	Density:  uiStructural.DataTableDensityDense,
	TextCase: uiToolset.TextCaseUpper,
})

Comfortable (default), headers as typed

Name Status CPU cores Actions
alpharunning2
bravorunning4
charliestopped1

Dense with uppercase headers

Name Status CPU cores Actions
alpharunning2
bravorunning4
charliestopped1
Sticky Header
Sticky Header

IsHeaderSticky pins the header and caps the scroll container, so the header stays visible while the body scrolls.

Usage

@uiStructural.DataTable(uiStructural.DataTableSettings[Record]{
	Columns:        columns,
	Rows:           records,
	IsHeaderSticky: true,
})

Name Status CPU cores
alpharunning2
bravorunning4
charliestopped1
deltarunning8
echorunning2
foxtrotstopped16
golfrunning2
hotelrunning4
indiastopped1
juliettrunning8
kilorunning2
limastopped16
mikerunning2
novemberrunning4
oscarstopped1
paparunning8
quebecrunning2
romeostopped16
sierrarunning2
tangorunning4
uniformstopped1
victorrunning8
whiskeyrunning2
xraystopped16
yankeerunning2
Empty States
Empty States

With no rows the table renders the EmptyState slot. Without the slot it renders the default message.

Usage

@uiStructural.DataTable(uiStructural.DataTableSettings[Record]{
	Columns:    columns,
	Rows:       nil,
	EmptyState: DataTableDemoEmptyState(),
})

Custom EmptyState

Name Status CPU cores

No servers yet

Create a server to see it listed here.

Default empty state

Name Status CPU cores
No records found.

.FilterBar

A filter bar renders one editor per declared filter and shows the active filters as removable chips.

Usage

@uiStructural.FilterBar(uiStructural.FilterBarSettings{
	Filters: []uiStructural.FilterSettings{
		{Key: "name", Label: "Name", Kind: uiStructural.FilterKindTextContains},
		{Key: "status", Label: "Status", Kind: uiStructural.FilterKindEnumSelect, Options: statusOptions},
		{Key: "cpu", Label: "CPU", Kind: uiStructural.FilterKindNumberRange},
	},
	ValuesTwoWayStatePath: "filterValues",

	// OptionalFields
	OnChangeFunc: "changeCount = changeCount + 1",
})

Live Example

All three filter kinds at once: text contains, enum select, and number range, with removable chips.

Name
Status
Status
CPU min
CPU max
Name:
Status:
CPU:

Values: · OnChangeFunc calls:

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Query Param Names
Query Param Names

QueryParamName renames the filter in the DataTable URL template. Without it the filter Key is the parameter name.

Usage

@uiStructural.FilterBar(uiStructural.FilterBarSettings{
	Filters: []uiStructural.FilterSettings{
		{
			Key:            "environment",
			Label:          "Environment",
			Kind:           uiStructural.FilterKindEnumSelect,
			Options:        buildDemoEnvironmentOptions(),
			QueryParamName: "recordEnvironment",
		},
	},
	ValuesTwoWayStatePath: "filterValues",
})
Environment
Environment
Environment:
Enum Radio Group Prefix
Enum Radio Group Prefix

EnumSelectRadioGroupNamePrefix namespaces the generated radio inputs of enum selects, so two filter bars on one page do not collide.

Usage

@uiStructural.FilterBar(uiStructural.FilterBarSettings{
	Filters: []uiStructural.FilterSettings{
		{Key: "region", Label: "Region", Kind: uiStructural.FilterKindEnumSelect, Options: buildDemoRegionOptions()},
	},
	ValuesTwoWayStatePath: "filterValues",

	// OptionalFields
	EnumSelectRadioGroupNamePrefix: "myForm",
})
Region
Region
Region:
Dropdown Background
Dropdown Background

DropdownBackgroundColor paints the enum select dropdown with a Tailwind background token. DataTable forwards it as FilterDropdownBackgroundColor.

Usage

@uiStructural.FilterBar(uiStructural.FilterBarSettings{
	Filters: []uiStructural.FilterSettings{
		{Key: "status", Label: "Status", Kind: uiStructural.FilterKindEnumSelect, Options: statusOptions},
	},
	ValuesTwoWayStatePath: "filterValues",

	// OptionalFields
	DropdownBackgroundColor: "primary-500/95",
})
Status
Status
Status:
Multi-Value Filter
Multi-Value Filter

FilterKindMultiEnumSelect holds an array of selected values under one key. The chip lists every value, and the DataTable URL repeats the parameter once per value.

Usage

@uiStructural.FilterBar(uiStructural.FilterBarSettings{
	Filters: []uiStructural.FilterSettings{
		{Key: "status", Label: "Status", Kind: uiStructural.FilterKindMultiEnumSelect, Options: statusOptions},
	},
	ValuesTwoWayStatePath: "filterValues",
})
Status
Status
Status:

.Pagination

Pagination splits records into pages and lets the user move between them.

Usage

@uiStructural.Pagination(uiStructural.PaginationSettings{
	PageNumberTwoWayStatePath:   "pageNumber",
	ItemsPerPageTwoWayStatePath: "itemsPerPage",
	ItemsTotal:                  240,

	// OptionalFields
	OnChangeFunc: "changeCount = changeCount + 1",
})

Live Example

Page navigation and a page-size select bound to Alpine state.

pageNumber: · itemsPerPage: · OnChangeFunc calls:

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Page-Size Choices
Page-Size Choices

ItemsPerPageSizeChoices replaces the default page-size options in the select.

Usage

@uiStructural.Pagination(uiStructural.PaginationSettings{
	PageNumberTwoWayStatePath:   "pageNumber",
	ItemsPerPageTwoWayStatePath: "itemsPerPage",
	ItemsTotal:                  240,

	// OptionalFields
	ItemsPerPageSizeChoices: []uint{5, 10, 25},
})
Disabled Binding
Disabled Binding

IsDisabledOneWayStatePath greys out the controls while a request is in flight.

Usage

@uiStructural.Pagination(uiStructural.PaginationSettings{
	PageNumberTwoWayStatePath:   "pageNumber",
	ItemsPerPageTwoWayStatePath: "itemsPerPage",
	ItemsTotal:                  240,

	// OptionalFields
	IsDisabledOneWayStatePath: "isPaginationDisabled",
})
Hidden On Single Page
Hidden On Single Page

IsHiddenWhenSinglePage hides only the page-number controls while the records fit on one page. The readout and the items-per-page select stay visible, and the controls return when a smaller page size needs more pages.

Usage

@uiStructural.Pagination(uiStructural.PaginationSettings{
	PageNumberTwoWayStatePath:   "pageNumber",
	ItemsPerPageTwoWayStatePath: "itemsPerPage",
	ItemsTotal:                  10,

	// OptionalFields
	IsHiddenWhenSinglePage: true,
})

One page: only the readout and page size

10 records at 50 per page fit on one page. Pick 5 per page to reveal the page-number controls.

Two pages: pagination shows

.PageHeading

The page heading block for both page titles and section headings: header title, optional icon and description, and a right-aligned action slot. One component with a Level setting so pages stop hand-rolling headers.

Usage

@uiStructural.PageHeading(uiStructural.PageHeadingSettings{
	HeaderTitle: "Records",
	Level:       uiStructural.PageHeadingLevelPage,

	// OptionalFields
	Description:    "Manage the server records",
	HeaderIcon:     "ph-table",
	ActionsContent: PageHeadingDemoActions(),
})

Live Example

The complete page-level heading: title, icon, description, and actions.

Records

Manage the server records and their lifecycle.

Advanced Examples

Open a panel to see one variation with its settings and the rendered result.

Title Only
Title Only

With no icon, sub-heading, or actions the heading is a single line.

Usage

@uiStructural.PageHeading(uiStructural.PageHeadingSettings{
	HeaderTitle: "Title Only",
	Level:       uiStructural.PageHeadingLevelSection,
})

Title Only

Levels & Sizes
Levels & Sizes

Level page renders the h1 page header and defaults to xl. Level section renders the h2 section heading and defaults to lg. HeaderSize scales either level: xs, sm, md, lg, or xl.

Usage

@uiStructural.PageHeading(uiStructural.PageHeadingSettings{
	HeaderTitle: "Records",
	Level:       uiStructural.PageHeadingLevelPage,

	// OptionalFields
	HeaderSize: uiDisplay.HeaderSizeSm,
})

Page Level

Section Level

xs

sm

md

lg

xl

Icon Styles
Icon Styles

HeaderIcon stamps a Phosphor icon on the heading. Color and position style it. A section-level icon carries a chip background by default.

Usage

@uiStructural.PageHeading(uiStructural.PageHeadingSettings{
	HeaderTitle: "Records",

	// OptionalFields
	HeaderIcon:       "ph-star",
	HeaderIconColor:  "amber-400",
	HeaderIconPosition: uiDisplay.HeaderIconPositionLeft,
})

Amber Star

Icon on Left

Section Chip

State-Bound Title
State-Bound Title

HeaderTitleOneWayStatePath and HeaderSubHeadingOneWayStatePath drive the heading text from Alpine state.

Usage

@uiStructural.PageHeading(uiStructural.PageHeadingSettings{
	HeaderTitle: "Records",

	// OptionalFields
	HeaderTitleOneWayStatePath:      "pageTitle",
	HeaderSubHeadingOneWayStatePath: "pageSubHeading",
})

Live Title

Text Case
Text Case

TextCase transforms the title and description. It accepts uiToolset.TextCaseNone (the default, as typed), TextCaseLower, TextCaseUpper, or TextCaseCapitalize.

Usage

@uiStructural.PageHeading(uiStructural.PageHeadingSettings{
	HeaderTitle: "Network Interfaces",
	Level:       uiStructural.PageHeadingLevelSection,

	// OptionalFields
	TextCase: uiToolset.TextCaseUpper,
})

Network Interfaces

Loading...