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",
	Shape:     uiForm.CheckboxInputShapeRounded,
})
Alpine.js Parent State (x-data)
<div x-data="{hasAcceptedTerms: false}"></div>
<div x-data="{selectedFruits: ['apple']}"></div>

Live Examples

Boolean state

Value:

Indeterminate state

Values:

Shapes

Sizes

Label position

States

Checked colors

.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",
		},
		{
			Label:           "Option 2",
			StateValue:      "option2",
			TwoWayStatePath: "groupSelection",
			InputId:         "groupOption2",
			InputName:       "group1",
		},
	},

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

Live Example

Select an option

.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

Basic Input

Name

Value & IsReadOnly

Name

InputTypeNumberMin, Max & Step

Name

AffixLeftValue & AffixRightValue

Name
goinfinite.dev/
Name
.jpg

HintValue & HintDisplay

Name
This is a helpful hint displayed as a description below the input.
Name

HintIconStyle

Name

.MultiSelectInput

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

Usage

(w/FlatOptions)
@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: }"></div>

Live Example

Countries

Usage

(w/LabelValueOptions)
@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: }"></div>

Live Example

Countries

Usage

(w/LabelValueOptions and LabelHtml)
@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: }"></div>

Live Example

Click the dropdown to see the HTML labels.

Countries

Usage

(w/HintValue & HintDisplay)
@uiForm.MultiSelectInput(uiForm.MultiSelectInputSettings{
	InputName: "countries",
	Label:     "Countries",

	// OptionalFields
	FlatOptions:     []string{"Argentina", "Brazil", "Chile"},
	TwoWayStatePath: "countries",
	HintValue:       "This is a helpful hint displayed as a description below the multi-select.",
	HintDisplay:     uiForm.InputHintDisplayDescription,
})
Alpine.js Parent State (x-data)
<div x-data="{countries: }"></div>

Live Example

HintValue & HintDisplay

Countries
This is a helpful hint displayed as a description below the multi-select.
Countries

HintIconStyle

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",
})
@uiForm.RadioInput(uiForm.RadioInputSettings{
	Label:           "Option 2",
	StateValue:      "option2",
	TwoWayStatePath: "selectedOption",
	InputId:         "radioOption2",
	InputName:       "options",
})
Alpine.js Parent State (x-data)
<div x-data="{selectedOption: 'option2'}"></div>

Live Example

.SelectInput

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

Usage

(w/FlatOptions)
@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: ''}"></div>

Live Example

Country
Country

Usage

(w/LabelValueOptions)
@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: ''}"></div>

Live Example

Country
Country

Usage

(w/LabelValueOptions and LabelHtml)
@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: ''}"></div>

Live Example

Click the dropdown to see the HTML labels.

Country
Country

Usage

(w/HintValue & HintDisplay)
@uiForm.SelectInput(uiForm.SelectInputSettings{
	InputName: "countryHintDescription",
	Label:     "Country",

	// OptionalFields
	FlatOptions:              []string{"Argentina", "Brazil", "Chile"},
	TwoWayStatePath:          "country",
	ShouldIncludeBlankOption: true,
	HintValue:                "This is a helpful hint displayed as a description below the select.",
	HintDisplay:              uiForm.InputHintDisplayDescription,
})
Alpine.js Parent State (x-data)
<div x-data="{country: ''}"></div>

Live Example

HintValue & HintDisplay

Country
Country
This is a helpful hint displayed as a description below the select.
Country
Country

HintIconStyle

Country
Country

Usage

(w/OnChangeFunc)
@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: '', changeCount: , onCountryChange() { this.changeCount++ }}"></div>

Live Example

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",
	IsRequired:      false,
	IsReadOnly:      false,
})
Alpine.js Parent State (x-data)
<div x-data="{description: ''}"></div>

Live Example

Description

Value & IsReadOnly

Description

HintValue & HintDisplay

Description
This is a helpful hint displayed as a description below the textarea.
Description

HintStatePath

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",
})
@uiForm.ToggleSwitch(uiForm.ToggleSwitchSettings{
	Label:           "Email notifications",
	TwoWayStatePath: "selectedChannels",
	CustomValue:     "email",
	InputName:       "channels",
})
Alpine.js Parent State (x-data)
<div x-data="{isNotificationsEnabled: false}"></div>
<div x-data="{selectedChannels: ['email']}"></div>

Live Examples

Boolean state

Value:

Array state

Values:

Sizes

Label position

Color variants

Required state

Disabled state

@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(),
			Icon: "ph-info",
		},
		{
			Title: "Section 2",
			Content: AccordionDemoSection2(),
		},
		{
			Title: "Section 3",
			Content: AccordionDemoSection3(),
		},
	},
})

Live Example

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.

.Alert

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

Usage

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

Live Example

Alert Variations

Flashy Customization Examples

Alpine.js Integration

Alpine.js Parent State (x-data)
<div x-data="{alertMessage: 'Dynamic alert content!', isAlertCloseable: true}"></div>

Dynamic Content

Dynamic Close Button

.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
	HideDelaySeconds:             "1",
	BackgroundColor:              "rgb(23, 23, 23)", // neutral-800
	TextMessage:                  "Loading...",
	TextColor:                    "rgb(250, 250, 250)", // neutral-50
	TextSize:                     uiDisplay.CloakLoadingTextSizeMd,
	Icon:                         "ph-compass-rose",
	IconSize:                     uiDisplay.CloakLoadingIconSizeLg,
	IconColor:                    "rgb(59, 130, 246)", // primary-400
	IconAnimationName:            uiDisplay.CloakLoadingAnimationNameSpin,
	IconAnimationDurationSeconds: "3",
})
Keep in mind that the colors must be set as rgb(a), hex or hsl(a) values as 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.

.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{
	// OptionalFields
	IsLoadingOneWayStatePath: "isLoading",
	BackgroundColor:          "neutral-900/80",
	Icon:                     "ph-compass-rose",
	IconSize:                 uiDisplay.LoadingOverlayIconSizeMd,
	AnimationName:            uiDisplay.LoadingOverlayAnimationNameSpin,
	AnimationDurationSeconds: "2",
})

Live Example

Alpine.js Parent State (x-data)
<div x-data="{isLoading: false}"></div>

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

.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",
	OuterRadius: uiDisplay.TagRadiusMd,
	InnerIcon: "ph-warning",
	InnerLabel: "Warning",
	Size: uiDisplay.TagSizeXs,
})

Live Example

TagSizeXs to TagSizeXl

Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning

TagRadiusNone to TagRadiusFull
(OuterRadius & InnerRadius)

Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning

OuterRingColor
(w/ OuterBackgroundColor "transparent")

Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning

OuterBackgroundColor
(w/o OuterRingColor)

Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning

InnerBackgroundColor

Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning
Info
Warning

Side Elements OnClickFunc

Add
Remove

OnRemoveFunc

Status: running

.Toast

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

Usage

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

Live Example

@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

ButtonSizeXs to ButtonSizeXl

Button Shapes

IconLeft & IconRight

Button Colors

Button with Ring

Button with Tooltip

IsDisabledOneWayStatePath

Count:

.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",
	TrackStartValue:           "0",
	TrackEndValue:             "100",
	TrackSteps:                "1",
})
Alpine.js Parent State (x-data)
<div x-data="{sliderValue: 50}"></div>

Live Example

Basic Slider

Value:

RangeSliderSizeXs to RangeSliderSizeXl

Thumb Shapes

Thumb Colors & Icons

ThumbValueBubble

Track Labels Positions

Track Colors & Icons

Track Ticks

Dual Mode

Price Range: $ - $

Initial State Normalization

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

Unnormalized Initial State

Raw Range: $ - $

@uiStructural

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

.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. HeaderTextCase changes the header capitalization. Both tables use the same columns and rows.

Usage

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

Comfortable (default) with lowercase headers

Name Status CPU cores
alpharunning2
bravorunning4
charliestopped1

Dense with uppercase headers

Name Status CPU cores
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

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

Values: · OnChangeFunc calls:

.Pagination

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

Usage

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

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

Live Example

pageNumber: · itemsPerPage: · OnChangeFunc calls:

Loading...