• Documentation

Getting Started

Learn how to install and use PopUI in your projects.

PopUI Go uses Templ to create template wrappers that define PopUI components, sharing styles with the base PopUI Svelte components.

Installation

Install the PopUI Go package:

Building

In order to generate the CSS, the tailwindcss application must be installed in your system. We recommend using brew:

To generate all the resources, run:

Documentation Site

Compile the project into the public directory with a single index.html:

Run a development server to quickly test template changes using the air utility. This ensures Tailwind classes, generated code, and the binary are correctly prepared:

Examples

The examples directory contains standalone projects that demonstrate how to use PopUI components in different scenarios. Run the development server and visit the links below:

  • Admin — An admin panel with sidebar navigation, tables, and action buttons.
  • App — A simple app layout with a header, main content area, and footer.
  • Console — A minimal console layout with basic content.
  • Prose — A prose-styled article page showcasing typography and rich text formatting.
  • Wizard — A multi-step wizard flow with forms, file uploads, and confirmation screens.

Icons

Browse the full set of icons available in PopUI. Click any icon to copy its usage code.

Activity Copied!
AddCircle Copied!
Add Copied!
Alert Copied!
Any Copied!
Archive Copied!
ArrowDown Copied!
ArrowLeft Copied!
ArrowRight Copied!
ArrowUp Copied!
Asterisk Copied!
Batch Copied!
Bell Copied!
Billing Copied!
Block Copied!
Bold Copied!
Bot Copied!
Box Copied!
Brackets Copied!
Calculator Copied!
Calendar Copied!
CheckBadge Copied!
CheckCircle Copied!
ChevronDown Copied!
ChevronLeft Copied!
ChevronRight Copied!
ChevronUp Copied!
CircleOutline Copied!
Close Copied!
CodeBlock Copied!
CodeFork Copied!
Code Copied!
Collapse Copied!
Command Copied!
Community Copied!
Company Copied!
Conditions Copied!
Connect Copied!
CrumpledPaper Copied!
Cube Copied!
Dashboard Copied!
Delete Copied!
Domain Copied!
DoubleArrow Copied!
Download Copied!
Drag Copied!
DropdownDown Copied!
DropdownUp Copied!
Duplicate Copied!
Edit Copied!
Enter Copied!
Envelope Copied!
Erase Copied!
Exchange Copied!
Expand Copied!
ExternalLink Copied!
Failure Copied!
Filter Copied!
Flag Copied!
Flask Copied!
FolderL Copied!
Folder Copied!
Gobl Copied!
Gov Copied!
Handshake Copied!
Hashtag Copied!
Header Copied!
Hide Copied!
History Copied!
IdBack Copied!
IdFront Copied!
If Copied!
InfoBold Copied!
Info Copied!
Invoice Copied!
Invopop Copied!
Italic Copied!
Key Copied!
Learn Copied!
Less Copied!
Link Copied!
List Copied!
Loader Copied!
Lock Copied!
Logout Copied!
Menu Copied!
Note Copied!
Notification Copied!
Ok Copied!
OldVersion Copied!
Options Copied!
Order Copied!
OrderedList Copied!
Payment Copied!
Picture Copied!
Pin Copied!
Placeholder Copied!
Pops Copied!
Preview Copied!
Published Copied!
Pulse Copied!
Puzzle Copied!
Question Copied!
Queue Copied!
Quote Copied!
Receipt Copied!
Reload Copied!
Replace Copied!
Reset Copied!
Rocket Copied!
Running Copied!
Save Copied!
ScrollBottom Copied!
ScrollLeft Copied!
ScrollRight Copied!
ScrollTop Copied!
Search Copied!
Send Copied!
Settings Copied!
Shortcut Copied!
SidebarHide Copied!
SidebarShow Copied!
Sign Copied!
Signature Copied!
Skip Copied!
Slash Copied!
Sleep Copied!
Sliders Copied!
SortAscending Copied!
SortDescending Copied!
SquareCheck Copied!
Stack Copied!
Stamp Copied!
StatusSquare Copied!
Status Copied!
Stop Copied!
Success Copied!
Support Copied!
Tables Copied!
Tag Copied!
Team Copied!
Theme Copied!
Tick Copied!
Unarchive Copied!
UnorderedList Copied!
Unpin Copied!
Upload Copied!
User Copied!
Van Copied!
View Copied!
WarningBold Copied!
WarningOutline Copied!
Warning Copied!
Workflow Copied!
Workspace Copied!
World Copied!

Tokens

Tailwind CSS design tokens including colors, spacing, shadows, and typography.

Token Colors

Foreground

foreground
Copied
Default text color
foreground-default-secondary
Copied
Secondary text
foreground-default-tertiary
Copied
Tertiary text
foreground-inverse
Copied
Inverse (on dark bg)
foreground-inverse-secondary
Copied
Inverse secondary
foreground-accent
Copied
Accent text
foreground-selected
Copied
Selected state text
foreground-success
Copied
Success text
foreground-warning
Copied
Warning text
foreground-critical
Copied
Critical/error text
foreground-info
Copied
Info text
foreground-attention
Copied
Attention text

Background

background
Copied
Default background
background-default-secondary
Copied
Secondary background
background-default-tertiary
Copied
Tertiary background
background-default-tertiary-hover
Copied
Tertiary hover
background-default-bold
Copied
Bold background
background-default-negative
Copied
Negative background
background-accent
Copied
Accent background
background-accent-hover
Copied
Accent hover
background-selected
Copied
Selected state
background-selected-hover
Copied
Selected hover
background-success
Copied
Success background
background-success-bold
Copied
Success bold
background-warning
Copied
Warning background
background-warning-bold
Copied
Warning bold
background-critical
Copied
Critical background
background-critical-bold
Copied
Critical bold
background-info
Copied
Info background
background-info-bold
Copied
Info bold
background-attention
Copied
Attention background

Border

border
Copied
Default border
border-default-secondary
Copied
Secondary border
border-default-secondary-hover
Copied
Secondary hover
border-default-tertiary
Copied
Tertiary border
border-inverse
Copied
Inverse border
border-inverse-secondary
Copied
Inverse secondary
border-selected
Copied
Selected border
border-selected-bold
Copied
Selected bold border
border-warning
Copied
Warning border
border-warning-bold
Copied
Warning bold
border-critical-bold
Copied
Critical border

Icon

icon
Copied
Default icon color
icon-default-secondary
Copied
Secondary icon
icon-default-bold
Copied
Bold icon
icon-inverse
Copied
Inverse icon
icon-inverse-secondary
Copied
Inverse secondary
icon-accent
Copied
Accent icon
icon-selected
Copied
Selected icon
icon-success
Copied
Success icon
icon-warning
Copied
Warning icon
icon-critical
Copied
Critical icon
icon-info
Copied
Info icon
icon-attention
Copied
Attention icon

Document Types

foreground-document-pdf
Copied
PDF text
foreground-document-xml
Copied
XML text
foreground-document-png
Copied
Image text
background-document-pdf
Copied
PDF background
background-document-xml
Copied
XML background
background-document-png
Copied
Image background
border-document-pdf
Copied
PDF border
border-document-xml
Copied
XML border
border-document-png
Copied
Image border
icon-document-pdf
Copied
PDF icon
icon-document-xml
Copied
XML icon
icon-document-png
Copied
Image icon

Status Colors

status-draft
Copied
Draft status
status-processing
Copied
Processing status
status-registered
Copied
Registered status
status-sent
Copied
Sent status
status-received
Copied
Received status
status-paid
Copied
Paid status
status-completed
Copied
Completed status
status-error
Copied
Error status
status-rejected
Copied
Rejected status
status-void
Copied
Void status
status-invalid
Copied
Invalid status
status-empty
Copied
Empty status

Spacing & Layout

Border Radius

sm
Copied
4px
md
Copied
6px
lg
Copied
8px
xl
Copied
10px
2xl
Copied
12px

Shadows

shadow
Copied
Default shadow
shadow-sm
Copied
Elevation: cards and rows
shadow-lg
Copied
Elevation: panels and popovers
shadow-xl
Copied
Elevation: dialogs and drawers
shadow-button-default
Copied
Default button shadow
shadow-button-primary
Copied
Primary button shadow
shadow-none
Copied
No shadow

Typography

Font Family

font-sans
Copied
Inter, sans-serif
The quick brown fox
font-mono
Copied
CommitMono, monospace
const x = 42;

Font Weights

font-normal
Copied
font-weight: 400
The quick brown fox
font-medium
Copied
font-weight: 500
The quick brown fox
font-semibold
Copied
font-weight: 600
The quick brown fox

Text Sizes

text-2xl
Copied
24px / 32px
The quick brown fox
text-xl
Copied
20px / 28px
The quick brown fox
text-lg
Copied
16px / 24px
The quick brown fox
text-md
Copied
15px / 22px
The quick brown fox
text-base
Copied
14px / 20px
The quick brown fox
text-sm
Copied
12px / 16px
The quick brown fox
text-xs
Copied
10px / 12px
The quick brown fox

Letter Spacing

tracking-tightest
Copied
-0.29px / for text-2xl
The quick brown fox
tracking-tighter
Copied
-0.24px / for text-xl
The quick brown fox
tracking-tight
Copied
-0.16px / for text-lg
The quick brown fox
tracking-normal
Copied
-0.07px / for text-base
The quick brown fox
tracking-wide
Copied
-0.036px / for text-sm
The quick brown fox

Accordion

Vertically stacked interactive sections to organize content.

Is it accessible?

Yes. It uses native HTML details/summary elements for full keyboard navigation and screen reader support.

Is it styled?

Yes. It comes with default styles using Tailwind CSS that you can customize.

12345678910111213141516171819202122232425262728293031
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ AccordionExample() { <div class="w-full space-y-2"> @popui.Accordion(props.Accordion{Open: true}) { @popui.AccordionTrigger() { Is it accessible? } @popui.AccordionContent() { @popui.Description() { Yes. It uses native HTML details/summary elements for full keyboard navigation and screen reader support. } } } @popui.Accordion() { @popui.AccordionTrigger() { Is it styled? } @popui.AccordionContent() { @popui.Description() { Yes. It comes with default styles using Tailwind CSS that you can customize. } } } </div> }

API Reference

Accordion

The main accordion container component using HTML details element.

NameTypeDefaultDescription
ID string-Unique identifier for the accordion element
Class string-Additional CSS classes to merge with base styles
Attributes templ.Attributes-Additional HTML attributes to apply to the details element
Open boolfalseWhether the accordion is initially expanded

AccordionTrigger

Clickable trigger element that toggles the accordion item.

NameTypeDefaultDescription
ID string-Unique identifier for the trigger element
Class string-Additional CSS classes to merge with base styles
Attributes templ.Attributes-Additional HTML attributes to apply to the summary element

AccordionContent

Collapsible content area of the accordion item.

NameTypeDefaultDescription
ID string-Unique identifier for the content element
Class string-Additional CSS classes to merge with base styles
Attributes templ.Attributes-Additional HTML attributes to apply to the content div

App

The main application layout component with header, nav, aside, main, and footer sections. Use this as the base for all popui applications, and extend as needed.

Basic App

Simple app with a header, main content area, and footer.

1234567891011121314151617181920212223242526272829303132
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ AppExample() { @popui.App(props.App{Title: "Application"}) { @popui.Header(props.Header{ Breadcrumbs: []props.Breadcrumb{{Label: "Example"}}, }) { @popui.Button(props.Button{Variant: "primary"}) { @icons.Add() <span>New Item</span> } } @popui.Main(props.Main{Center: true}) { @popui.Article() { @popui.Block(props.Block{ Class: "items-center justify-center border border-dashed border-border-document-png bg-background-document-png rounded-2xl text-foreground-default-tertiary", }) { This is where the page contents goes. } } } @popui.Footer() { <span class="text-sm text-foreground-default-secondary">&copy; 2025 Invopop Inc.</span> } } }

Configuration App

Simple app with only a basic content area.

123456789101112131415161718192021222324252627
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ AppConfigExample() { @popui.App(props.App{Title: "Configure"}) { @popui.Main(props.Main{Center: true}) { @popui.Article() { @popui.Input(props.Input{ ID: "name-for-app-config", Label: "Name", Type: "text", Placeholder: "Your Name", }) @popui.Input(props.Input{ ID: "email-for-app-config", Label: "Email", Type: "email", Placeholder: "email@example.com", }) } } } }

App Popup

App layout with a header and closer button..

12345678910111213141516171819202122232425262728293031323334353637383940414243
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ AppPopupExample() { @popui.App(props.App{Title: "Application Popup"}) { @popui.Header(props.Header{ Title: appPopupTitle(), }) { @popui.Button(props.Button{Variant: props.ButtonVariantSecondary}) { Add New } } @popui.Main() { @popui.Article(props.Article{FullWidth: true}) { <div class="w-full flex flex-1 items-center justify-center min-h-10 p-4 gap-2 border border-dashed border-border-document-png bg-background-document-png rounded-2xl text-foreground-default-tertiary"> This is where the page contents goes. </div> } } @popui.Footer() { @popui.Button(props.Button{Variant: props.ButtonVariantPrimary}) { Next } } } } templ appPopupTitle() { @popui.Button(props.Button{ Variant: props.ButtonVariantTransparent, Class: "p-2", }) { @icons.Close() } <span> Popup Example </span> }

App with Sidebar Navigation

App layout that includes a sidebar navigation menu alongside the main content area.

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ AppWithSidebarExample() { @popui.App(props.App{Title: "Application With Sidebar"}) { @popui.Sidebar() { @popui.SidebarHeader() { @popui.InvopopLogoSquare() <span class="flex-1">Sidebar</span> @popui.Button(props.Button{ Variant: props.ButtonVariantTransparent, Size: props.ButtonSizeIcon, Class: "-mr-1", Attributes: templ.Attributes{ "data-sidebar-hide": "", }, }) { @icons.SidebarHide() } } @popui.SidebarContent() { @popui.SidebarSection(props.SidebarSection{Title: "Section 1"}) { @popui.SidebarItem(props.SidebarItem{Href: "#", Selected: true}) { Overview } @popui.SidebarItem(props.SidebarItem{Href: "#"}) { Dashboard } } } } @popui.Header(props.Header{ Breadcrumbs: []props.Breadcrumb{{Label: "Example"}}, }) { @popui.Button(props.Button{Variant: "primary"}) { @icons.Add() <span>New Item</span> } } @popui.Main(props.Main{Center: true}) { @popui.Article(props.Article{Title: "App", Description: "Example of configuring the app with props"}) { @popui.Section(props.Section{Title: "Configuration", Description: "Example of section with title and description"}) { @popui.Input(props.Input{ ID: "name-for-app-with-sidebar", Label: "Name", Type: "text", Placeholder: "Your Name", }) @popui.Input(props.Input{ ID: "email-for-app-with-sidebar", Label: "Email", Type: "email", Placeholder: "email@example.com", }) } @popui.Section(props.Section{Title: "Preferences", Description: "Example of section with title and description"}) { @popui.Checkbox(props.Checkbox{ ID: "subscribe-for-app-with-sidebar", Label: "Subscribe to newsletter", }) } } } @popui.Footer() { <span class="text-sm text-foreground-default-secondary">&copy; 2026 Invopop Inc.</span> } } }

App with table and pagination

App layout that includes a full width table and pagination in the main content area.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ AppWithTableExample() { @popui.App(props.App{Title: "Application With Table"}) { @popui.Header(props.Header{ Breadcrumbs: []props.Breadcrumb{{Label: "Example"}}, }) { @popui.Button(props.Button{Variant: "primary"}) { @icons.Add() <span>New Item</span> } } @popui.Main() { @popui.Table() { <thead> <tr> <th>Invoice ID</th> <th>Customer</th> <th>Amount</th> <th>Status</th> </tr> </thead> <tbody> <tr> <td>INV-001</td> <td>Acme Corp</td> <td>$1,234.56</td> <td>Paid</td> </tr> <tr> <td>INV-002</td> <td>Tech Solutions</td> <td>$987.65</td> <td>Pending</td> </tr> <tr> <td>INV-003</td> <td>Global Inc</td> <td>$2,345.67</td> <td>Paid</td> </tr> </tbody> } @popui.TablePagination(props.TablePagination{ CurrentPage: 1, TotalPages: 260, TotalItems: 25991, RowsPerPage: 100, RowsPerPageOptions: []int{10, 25, 50, 100, 250}, ShowRowsPerPage: true, ItemsLabel: "invoices", FirstPageURL: "?page=1", PrevPageURL: "?page=0", NextPageURL: "?page=2", LastPageURL: "?page=260", }) { @popui.ButtonGroup() { @popui.Button(props.Button{ Type: "button", Size: "sm", Variant: "secondary", }) { Create Invoice } } } } } }

App with Aside Panel

App layout with an optional aside panel on the right side. The aside has a fixed width of 400px and appears between the header and footer.

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ AppWithAsideExample() { @popui.App(props.App{Title: "Application with Aside"}) { @popui.Header(props.Header{ Breadcrumbs: []props.Breadcrumb{{Label: "Example"}}, }) { @popui.Button(props.Button{Variant: "primary"}) { @icons.Add() <span>New Item</span> } } @popui.Main(props.Main{Center: false}) { @popui.Article() { @popui.Block() { <h2> Main Content Area </h2> <p> This is the main content area. The aside panel appears on the right side with a fixed width of 400px. </p> <p> The aside is optional - if not included, the main content area will take up the full width as usual. </p> } } } @popui.Aside() { @popui.Block(props.Block{Class: "p-4"}) { <h3> Aside Panel </h3> <p> This is the aside content. It appears on the right side with a fixed width of 400px. </p> @popui.Separator() <p> Use this for supplementary information, navigation, or contextual actions. </p> } } @popui.Footer() { <span class="text-sm text-foreground-default-secondary">&copy; 2025 Invopop Inc.</span> } } }

API Reference

App

Root application container for full-window apps. Sets up the basic HTML structure with head and body, and includes Alpine.js for interactivity. Designed to be standalone or embedded in the Invopop Console.

NameTypeDefaultDescription
Title string-Page title displayed in browser tab
Description string-Meta description for SEO
AccentColor string-Accent color for the application
Head templ.ComponentnilAdditional content to include in the <head> section
FillViewport boolfalsePin the document to the viewport height and stop the body from scrolling, so the App's h-full grid resolves and scrolling happens inside the content rather than the page. Required for a Table with StickyHeader to pin. Safe in an embedded iframe; leave false for normal scrolling documents
Data string-Alpine.js x-data attribute value for the application body's contents
HTMX boolfalseWhen true, includes the HTMX javascript library for enhanced interactivity
Importmap []props.ImportnilModule specifier mappings for an ES import map. Rendered as a <script type="importmap"> tag before module scripts. Order is preserved.
Modules []props.ModulenilES module scripts to include. Rendered as <script type="module"> tags after the importmap and before regular scripts.
Scripts []props.ScriptnilAdditional script paths to include in the head (alternative to defining in Head property)
Stylesheets []props.LinknilAdditional stylesheet links to include in the head (alternative to defining in Head property)

Main

Main content area wrapper for apps. Use this outside Header/Footer components. Contains the primary content and provides overflow handling.

NameTypeDefaultDescription
ID string-Unique identifier for the main element
Class string-Additional CSS classes to merge with main styles
Cloak boolfalseAdd x-cloak attribute to hide content until Alpine.js initializes
Data string-Alpine.js x-data attribute value for reactive state
Center boolfalseCenter the main content with a maximum width
Attributes templ.Attributes-Additional HTML attributes

Header

Header area for apps with optional breadcrumb navigation. Use directly inside App component, not inside Main. Sticky positioned at top.

NameTypeDefaultDescription
ID string-Unique identifier for the header element
Class string-Additional CSS classes to merge with header styles
Title templ.ComponentnilCustom title component displayed on the left side of the header before breadcrumbs
Data string-Alpine.js x-data attribute value for reactive state
Attributes templ.Attributes-Additional HTML attributes
Breadcrumbs []props.BreadcrumbnilNavigation breadcrumbs displayed on the left side of header

Footer

Footer component for apps with content justified to the end. Use directly inside App component, not inside Main.

NameTypeDefaultDescription
ID string-Unique identifier for the footer element
Class string-Additional CSS classes to merge with footer styles
Data string-Alpine.js x-data attribute value for reactive state
Attributes templ.Attributes-Additional HTML attributes

Article

Article component for app content with optional full-width mode.

NameTypeDefaultDescription
ID string-Unique identifier for the article element
Class string-Additional CSS classes to merge with article styles
FullWidth boolfalseMakes the article take the full width of the main content area while maintaining padding
Attributes templ.Attributes-Additional HTML attributes

Block

Block component for grouping related content within apps. Provides the same flex model as for Articles.

NameTypeDefaultDescription
ID string-Unique identifier for the block element
Class string-Additional CSS classes to merge with block styles
Attributes templ.Attributes-Additional HTML attributes

Nav

Navigation component for apps.

NameTypeDefaultDescription
ID string-Unique identifier for the nav element
Class string-Additional CSS classes to merge with nav styles
Data string-Alpine.js x-data attribute value for reactive state
Attributes templ.Attributes-Additional HTML attributes

Aside

Optional fixed-width sidebar component that appears on the right side of the app, next to the Main content area and between the Header and Footer. Has a fixed width of 400px with overflow scrolling.

NameTypeDefaultDescription
ID string-Unique identifier for the aside element
Class string-Additional CSS classes to merge with aside styles
Data string-Alpine.js x-data attribute value for reactive state
Attributes templ.Attributes-Additional HTML attributes

Sidebar

Navigation sidebar for admin panels. Renders a fixed-width nav element that collapses on small screens and expands on medium+ breakpoints.

NameTypeDefaultDescription
Title string-Title for the sidebar (currently unused in rendering, reserved for accessibility)
Class string-Additional CSS classes to merge with sidebar styles
Variant string-Visual style variant. Use "dark" for a dark background with inverse text and border colors.
Attributes templ.Attributes-Additional HTML attributes

SidebarHeader

Header area at the top of the sidebar, typically used for a logo or branding. Renders with a bottom border separator.

NameTypeDefaultDescription

SidebarContent

Scrollable content area of the sidebar that grows to fill available space. Contains sidebar sections and navigation items.

NameTypeDefaultDescription

SidebarSection

Groups related navigation items within the sidebar content area. Renders an optional title and a list of sidebar items.

NameTypeDefaultDescription
Title string-Section heading displayed above the navigation items
Class string-Additional CSS classes to merge with section styles
Attributes templ.Attributes-Additional HTML attributes

SidebarItem

Individual navigation link within a sidebar section. Renders as an anchor element inside a list item with hover and selected states.

NameTypeDefaultDescription
ID string-Unique identifier for the anchor element
Class string-Additional CSS classes to merge with item styles
Selected boolfalseWhen true, applies the active/selected background style
Href templ.SafeURL-Navigation URL for the sidebar link
Attributes templ.Attributes-Additional HTML attributes applied to the anchor element

SidebarFooter

Footer area at the bottom of the sidebar with a top border separator. Useful for user profile links or secondary actions.

NameTypeDefaultDescription

Avatar

Display user profile images or initials in circular containers.

J
X
12345678910111213
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ AvatarExample() { <div class="flex items-center gap-4"> @popui.Avatar(props.Avatar{Initial: "J"}) @popui.Avatar(props.Avatar{Size: "lg", Initial: "X"}) </div> }

Sizes

Avatar comes in two sizes: default (small) and large (lg).

D
L
12345678910111213
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ AvatarSizesExample() { <div class="flex items-center gap-4"> @popui.Avatar(props.Avatar{Initial: "D"}) @popui.Avatar(props.Avatar{Size: "lg", Initial: "L"}) </div> }

With Images

You can pass an Image component as a child instead of using the Initial prop.

1234567891011121314151617
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ AvatarWithImagesExample() { <div class="flex items-center gap-4"> @popui.Avatar() { @popui.Image(props.Image{Src: "https://i.pravatar.cc/150?img=1"}) } @popui.Avatar(props.Avatar{Size: "lg"}) { @popui.Image(props.Image{Src: "https://i.pravatar.cc/150?img=3"}) } </div> }

Colored Initials

Initials take up to three characters and an optional Color token. Use the document-* tokens with a mono font for file-type badges, e.g. as the leading slot of FileDownloadInfo.

XML
PDF
PNG
CSV
OK
JD
12345678910111213141516171819202122232425262728293031323334353637383940414243
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ AvatarColorsExample() { <div class="flex items-center gap-2"> @popui.Avatar(props.Avatar{ Initial: "XML", Color: "document-xml", Size: props.AvatarSizeLarge, Class: "rounded-md font-mono", }) @popui.Avatar(props.Avatar{ Initial: "PDF", Color: "document-pdf", Size: props.AvatarSizeLarge, Class: "rounded-md font-mono", }) @popui.Avatar(props.Avatar{ Initial: "PNG", Color: "document-png", Size: props.AvatarSizeLarge, Class: "rounded-md font-mono", }) @popui.Avatar(props.Avatar{ Initial: "CSV", Size: props.AvatarSizeLarge, Class: "rounded-md font-mono", }) @popui.Avatar(props.Avatar{ Initial: "OK", Color: "success", Size: props.AvatarSizeLarge, }) @popui.Avatar(props.Avatar{ Initial: "JD", Color: "accent", }) </div> }

API Reference

Avatar

Displays a user avatar with an image or initials in a circular container.

NameTypeDefaultDescription
ID string-Unique identifier for the avatar element
Class string-Additional CSS classes to merge with base styles
Attributes templ.Attributes-Additional HTML attributes to apply to the div element
Initial string-Text to display (typically initials) when no image is provided; up to three characters, longer values are truncated
Color string-Foreground color token for the initials: "accent", "success", "warning", "critical", "info", "document-xml", "document-pdf" or "document-png". Empty uses the secondary foreground
Size string"" (default)Size variant: "lg" for large (8x8), default is small (5x5)

Breadcrumbs

Navigation breadcrumbs to show the current page location.

12345678910111213141516171819202122
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ BreadcrumbsExample() { @popui.Breadcrumbs() { @popui.Breadcrumb(props.Breadcrumb{ Label: "Home", Href: "/", }) @popui.Breadcrumb(props.Breadcrumb{ Label: "Products", Href: "/products", }) @popui.Breadcrumb(props.Breadcrumb{ Label: "Electronics", }) } }

With Children

Use children instead of Label prop for custom content.

123456789101112131415161718192021222324
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ BreadcrumbsWithChildrenExample() { @popui.Breadcrumbs() { @popui.Breadcrumb(props.Breadcrumb{ Href: "/", }) { <span>🏠 Home</span> } @popui.Breadcrumb(props.Breadcrumb{ Href: "/products", }) { <span>📦 Products</span> } @popui.Breadcrumb(props.Breadcrumb{}) { <span>💻 Electronics</span> } } }

With Attributes

Use Attributes to attach HTMX or other custom attributes to breadcrumb links.

12345678910111213141516171819202122232425262728293031323334
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ BreadcrumbsWithAttributesExample() { @popui.Breadcrumbs() { @popui.Breadcrumb(props.Breadcrumb{ Label: "Home", Href: "/", Attributes: templ.Attributes{ "hx-get": "/", "hx-target": "#content", "hx-swap": "innerHTML", "hx-push-url": "/", }, }) @popui.Breadcrumb(props.Breadcrumb{ Label: "Products", Href: "/products", Attributes: templ.Attributes{ "hx-get": "/products", "hx-target": "#content", "hx-swap": "innerHTML", "hx-push-url": "/products", }, }) @popui.Breadcrumb(props.Breadcrumb{ Label: "Electronics", }) } }

API Reference

Breadcrumbs

Container component for breadcrumb navigation.

NameTypeDefaultDescription
ID string-Unique identifier for the breadcrumb element
Class string-Additional CSS classes to merge with breadcrumb styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)

Breadcrumb

Individual breadcrumb item. Renders as a link if Href is provided, otherwise as plain text.

NameTypeDefaultDescription
ID string-Unique identifier for the breadcrumb item element
Class string-Additional CSS classes to merge with item styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Label string-Text label for the breadcrumb item
Href templ.SafeURL-URL for the breadcrumb link. If empty, renders as plain text

Button

Trigger actions and events with customizable button components.

1234567891011
package examples import "github.com/invopop/popui.go" templ ButtonExample() { @popui.ButtonGroup() { @popui.Button() { Default Button } } }

Variants

Buttons come in different variants to communicate different actions: default, primary, secondary, danger, transparent, and inverse (for dark surfaces).

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ ButtonVariantsExample() { @popui.ButtonGroup() { @popui.Button() { @icons.User() Default } @popui.Button(props.Button{Variant: props.ButtonVariantPrimary}) { @icons.Download() Primary } @popui.Button(props.Button{Variant: props.ButtonVariantSecondary}) { @icons.Settings() Secondary } @popui.Button(props.Button{Variant: props.ButtonVariantDanger}) { @icons.Delete() Danger } @popui.Button(props.Button{Variant: props.ButtonVariantTransparent}) { @icons.Lock() Transparent } <div class="flex items-center rounded-md bg-background-default-negative px-2 py-1.5"> @popui.Button(props.Button{Variant: props.ButtonVariantInverse}) { @icons.Reload() Inverse } </div> @popui.Button(props.Button{Size: props.ButtonSizeIcon}) { @icons.Settings() } @popui.Button(props.Button{Variant: props.ButtonVariantPrimary, Size: props.ButtonSizeIcon}) { @icons.Add() } @popui.Button(props.Button{Variant: props.ButtonVariantSecondary, Size: props.ButtonSizeIcon}) { @icons.Settings() } @popui.Button(props.Button{Variant: props.ButtonVariantDanger, Size: props.ButtonSizeIcon}) { @icons.Delete() } @popui.Button(props.Button{Variant: props.ButtonVariantTransparent, Size: props.ButtonSizeIcon}) { @icons.Lock() } } }

Sizes

Buttons are available in small (sm), default (md), and icon sizes.

12345678910111213141516171819202122232425262728293031323334
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ ButtonSizesExample() { @popui.ButtonGroup() { @popui.Button(props.Button{ Variant: props.ButtonVariantPrimary, Size: props.ButtonSizeSmall, }) { Small } @popui.Button(props.Button{ Variant: props.ButtonVariantPrimary, }) { Default } @popui.Button(props.Button{ Variant: props.ButtonVariantPrimary, Size: props.ButtonSizeLarge, }) { Large } @popui.Button(props.Button{ Variant: props.ButtonVariantPrimary, Size: props.ButtonSizeIcon, }) { + } } }

With Content

Buttons can contain any content including text, icons, or combinations.

12345678910111213141516171819
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ ButtonWithIconsExample() { @popui.ButtonGroup() { @popui.Button(props.Button{Variant: props.ButtonVariantPrimary}) { Save } @popui.Button(props.Button{Variant: props.ButtonVariantDanger}) { @icons.Delete() Delete } } }

Disabled State

Buttons can be disabled to prevent user interaction.

1234567891011121314151617181920
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ ButtonDisabledExample() { @popui.ButtonGroup() { @popui.Button(props.Button{Disabled: true}) { Disabled Default } @popui.Button(props.Button{Variant: props.ButtonVariantPrimary, Disabled: true}) { Disabled Primary } @popui.Button(props.Button{Variant: props.ButtonVariantDanger, Disabled: true}) { Disabled Danger } } }

Anchor Button

Set the Href property to render a link styled as a button.

123456789101112131415161718192021222324
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ ButtonAnchorExample() { @popui.ButtonGroup() { @popui.Button(props.Button{ Variant: props.ButtonVariantPrimary, Href: "/docs", }) { Visit Website } @popui.Button(props.Button{ Variant: props.ButtonVariantSecondary, Href: "/docs", Target: "_blank", }) { Open in New Tab } } }

Button Group Alignment

ButtonGroup can align buttons to the left (default), center, or right using the Align property.

Left (default)

Center

Right

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ ButtonGroupAlignExample() { <div class="space-y-4"> <div> <p class="text-sm text-foreground-secondary mb-2">Left (default)</p> @popui.ButtonGroup() { @popui.Button(props.Button{Variant: props.ButtonVariantPrimary}) { @icons.Save() Save } @popui.Button(props.Button{Variant: props.ButtonVariantSecondary}) { Cancel } } </div> <div> <p class="text-sm text-foreground-secondary mb-2">Center</p> @popui.ButtonGroup(props.ButtonGroup{Align: props.ButtonGroupAlignCenter}) { @popui.Button(props.Button{Variant: props.ButtonVariantPrimary}) { @icons.Save() Save } @popui.Button(props.Button{Variant: props.ButtonVariantSecondary}) { Cancel } } </div> <div> <p class="text-sm text-foreground-secondary mb-2">Right</p> @popui.ButtonGroup(props.ButtonGroup{Align: props.ButtonGroupAlignRight}) { @popui.Button(props.Button{Variant: props.ButtonVariantPrimary}) { @icons.Save() Save } @popui.Button(props.Button{Variant: props.ButtonVariantSecondary}) { Cancel } } </div> </div> }

Copy to Clipboard

Setting Copy turns the button into a copy-to-clipboard control: the value renders in mono with a duplicate icon that flips to a tick on success. CopyPrefixLength / CopySuffixLength truncate the displayed value; the full value is copied.

12345678910111213141516171819
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ ButtonCopyToClipboardExample() { <div class="flex items-center gap-4"> @popui.Button(props.Button{ Copy: "go get github.com/invopop/popui.go", }) @popui.Button(props.Button{ Copy: "123e4567-e89b-12d3-a456-426614174000", CopyPrefixLength: 8, CopySuffixLength: 4, }) </div> }

API Reference

ButtonGroup

Container component for grouping multiple buttons horizontally with consistent spacing.

NameTypeDefaultDescription
ID string-Unique identifier for the element
Class string-Additional CSS classes to merge with button group styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Align stringleftHorizontal alignment: 'left' (default), 'center', or 'right'

Button

Button component that can render as either a <button> or <a> element. When Href is set, renders as an anchor link styled as a button.

NameTypeDefaultDescription
ID string-Unique identifier for the element
Class string-Additional CSS classes to merge with button styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Variant stringprimaryVisual style: 'primary', 'secondary', 'danger', 'transparent', or 'inverse' (for dark surfaces)
Size stringmdButton size: 'sm', 'md' (default), 'lg', or 'icon'
Type string-Button type: 'button', 'submit', or 'reset' (form buttons only)
Name string-Name attribute for form submission (form buttons only)
Value string-Value attribute for form submission (form buttons only)
Copy string-Turns the button into a copy-to-clipboard control for this value (form buttons only)
CopyPrefixLength int0Characters of the Copy value shown before the ellipsis; 0 with CopySuffixLength 0 shows it untruncated
CopySuffixLength int0Characters of the Copy value shown after the ellipsis
Form string-Associates button with a form by ID (form buttons only)
Disabled boolfalseDisables the button (form buttons only)
Autofocus boolfalseAutomatically focuses the button on page load (form buttons only)
Href templ.SafeURL-URL destination; when set, renders as an anchor link
Target string-Target attribute: '_blank', '_self', etc. (anchor buttons only)
Rel string-Rel attribute for link relationship (anchor buttons only)
Download boolfalseTriggers download of the linked resource (anchor buttons only)

Calendar

Dual-month, range-selection calendar with a preset rail and month navigation. Backed by the rangeCalendar Alpine controller.

123456789101112131415161718192021222324252627282930313233343536
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ CalendarExample() { <div x-data="{ show: false }" @click.outside="show = false" @popui-cal-confirm="show = false" @popui-cal-cancel="show = false" class="w-fit" > @popui.Button(props.Button{ Attributes: templ.Attributes{ "@click": "show = !show", }, }) { Open calendar } <div x-show="show" x-cloak class="mt-2"> @popui.Calendar(props.Calendar{ Name: "period", Presets: []props.CalendarPreset{ {Key: props.CalendarPresetThisMonth}, {Key: props.CalendarPresetLastMonth}, {Key: props.CalendarPresetThisQuarter}, {Key: props.CalendarPresetLastQuarter}, {Key: props.CalendarPresetCustom, Label: "Custom range"}, }, }) </div> </div> }

API Reference

Calendar

Calendar renders a dual month range picker with a preset rail and month navigation. All interactive state lives in the rangeCalendar Alpine controller that ships with popui.

NameTypeDefaultDescription
ID string-Sets the unique identifier of the root element.
Class string-Adds CSS classes that are merged with the base styling.
Attributes templ.Attributes-Applies additional HTML attributes to the root element.
Name string-Makes the calendar own its state. It declares its own rangeCalendar Alpine scope under this field name and wraps the grid in a bordered container. Leave it empty to render markup only inside a scope provided by an ancestor, which is how the Filter date range chip embeds it.
From string-Seeds the start of the initially selected range as an ISO date. It only applies when Name is set.
To string-Seeds the end of the initially selected range as an ISO date. It only applies when Name is set.
Presets []props.CalendarPresetdefaultConfigures the shortcuts shown in the preset rail. It defaults to the standard presets.

CalendarPreset

CalendarPreset is one shortcut in the preset rail. The date computation for each key lives in the rangeCalendar controller.

NameTypeDefaultDescription
Key string-Selects the built in date range. Use one of the CalendarPreset constants such as CalendarPresetThisMonth or CalendarPresetCustom.
Label stringKey defaultOverrides the text shown in the rail. It falls back to the standard label for the key when empty.

Card

Flexible container components for displaying content in a bordered box.

Card content goes here
12345678910111213
package examples import "github.com/invopop/popui.go" templ CardExample() { @popui.Card() { @popui.CardContent() { <div class="w-full flex items-center justify-center min-h-10 p-4 gap-2 border border-dashed border-border-document-png bg-background-document-png rounded-2xl text-foreground-default-tertiary"> Card content goes here </div> } } }

With Header

Cards can include a header with avatar, title, and subtitle using the CardHeader component.

J

John Doe

Software Engineer

This card includes a header with an avatar and title information.
12345678910111213141516171819202122232425
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ CardWithHeaderExample() { @popui.Card() { @popui.CardHeader(props.CardHeader{ Title: "John Doe", Subtitle: "Software Engineer", }) { @popui.Avatar(props.Avatar{ Size: "lg", Initial: "J", }) } @popui.CardContent() { <div class="w-full flex items-center justify-center min-h-10 p-4 gap-2 border border-dashed border-border-document-png bg-background-document-png rounded-2xl text-foreground-default-tertiary"> This card includes a header with an avatar and title information. </div> } } }

Disabled State

Cards can be disabled to indicate they are not interactive.

Disabled Card

Cannot be interacted with

This card is disabled.
1234567891011121314151617181920
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ CardDisabledExample() { @popui.Card(props.Card{Disabled: true}) { @popui.CardHeader(props.CardHeader{ Title: "Disabled Card", Subtitle: "Cannot be interacted with", }) @popui.CardContent() { <div class="w-full flex items-center justify-center min-h-10 p-4 gap-2 border border-dashed border-border-document-png bg-background-document-png rounded-2xl text-foreground-default-tertiary"> This card is disabled. </div> } } }

As Link

Cards can act as clickable links by providing an Href prop, rendering as an anchor element.

123456789101112131415161718192021222324252627
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ CardAsLinkExample() { @popui.Card(props.Card{ Href: "/profile", }) { @popui.CardHeader(props.CardHeader{ Title: "Clickable Card", Subtitle: "Click anywhere to navigate", }) { @popui.Avatar(props.Avatar{ Size: "lg", Initial: "C", }) } @popui.CardContent() { <div class="w-full flex items-center justify-center min-h-10 p-4 gap-2 border border-dashed border-border-document-png bg-background-document-png rounded-2xl text-foreground-default-tertiary"> This entire card is clickable. </div> } } }

Progress Bar

CardProgressBar displays progress with a visual indicator and optional counter.

Logo

Usage Statistics

Track your API consumption

API Requests · This month

7500 / 10000
123456789101112131415161718192021222324252627282930
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ CardProgressBarExample() { @popui.Card() { @popui.CardHeader(props.CardHeader{ Title: "Usage Statistics", Subtitle: "Track your API consumption", }) { @popui.Avatar(props.Avatar{ Size: "lg", }) { @popui.Image(props.Image{ Src: "https://i.pravatar.cc/150?img=68", Alt: "Logo", }) } } @popui.CardProgressBar(props.CardProgressBar{ Title: "API Requests", Subtitle: "This month", Current: 7500, Total: 10000, }) } }

Dashboard

Display multiple metrics with a plain grid of stat tiles inside CardContent — no dedicated component needed.

Monthly Overview

Key performance metrics

  • Revenue

    $12.5k

  • Orders

    243

  • Customers

    89

12345678910111213141516171819202122232425262728293031
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ CardDashboardExample() { @popui.Card() { @popui.CardHeader(props.CardHeader{ Title: "Monthly Overview", Subtitle: "Key performance metrics", }) @popui.CardContent() { <ul class="grid grid-cols-3 gap-x-3"> <li class="flex flex-col items-center py-3 px-2 rounded-md border border-border bg-background-default-secondary"> <p class="text-foreground-default-secondary text-sm">Revenue</p> <p class="text-foreground text-xl font-medium">$12.5k</p> </li> <li class="flex flex-col items-center py-3 px-2 rounded-md border border-border bg-background-default-secondary"> <p class="text-foreground-default-secondary text-sm">Orders</p> <p class="text-foreground text-xl font-medium">243</p> </li> <li class="flex flex-col items-center py-3 px-2 rounded-md border border-border bg-background-default-secondary"> <p class="text-foreground-default-secondary text-sm">Customers</p> <p class="text-foreground text-xl font-medium">89</p> </li> </ul> } } }

API Reference

Card

Main container component for displaying content in a bordered box.

NameTypeDefaultDescription
ID string-Unique identifier for the card element
Class string-Additional CSS classes to merge with card styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Href templ.SafeURL-URL to navigate to when card is clicked (renders as anchor)
Disabled boolfalseDisables the card and applies disabled styling

CardContent

Content container for cards with consistent padding and text styling.

NameTypeDefaultDescription
ID string-Unique identifier for the content element
Class string-Additional CSS classes to merge with content styles
Attributes templ.Attributes-Additional HTML attributes

CardHeader

Header component for cards. Expects Avatar or other content as children.

NameTypeDefaultDescription
ID string-Unique identifier for the header element
Class string-Additional CSS classes to merge with header styles
Attributes templ.Attributes-Additional HTML attributes
Title string-Main title text
Subtitle string-Secondary subtitle text

CardProgressBar

Displays progress with a visual bar and optional counter.

NameTypeDefaultDescription
ID string-Unique identifier for the progress bar element
Class string-Additional CSS classes to merge with progress bar styles
Attributes templ.Attributes-Additional HTML attributes
Title string-Main title text
Subtitle string-Secondary subtitle text
Current int640Current progress value
Total int640Total/maximum value for progress
HideCounter boolfalseHides the numeric counter display

CardDeck

Tinted container that stacks regular Cards into one visual unit.

Oct 01, 2025
Oct 31, 2025
Current
Enterprise
Documents: 100
Price: €0.00 / month
ChargebeeChargebee
Seats: 10
Price: €0.00 / month
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ CardDeckExample() { @popui.CardDeck() { @popui.CardDeckHead() { <div class="flex items-center gap-1"> <span>Oct 01, 2025</span> @icons.ArrowRight() <span>Oct 31, 2025</span> </div> @popui.TagStatus(props.TagStatus{Label: "Current", Status: "grey"}) } @popui.Card(props.Card{Class: "flex-row items-center gap-1.5 p-3"}) { <div class="flex grow items-center gap-1.5"> <span class="size-4 inline-flex items-center justify-center [&>svg]:size-full"> @icons.Invopop() </span> <span class="font-medium text-foreground">Enterprise</span> </div> <div class="flex items-center gap-4"> <div class="flex flex-wrap items-baseline gap-2 text-base justify-end"> <div class="flex items-baseline gap-1 text-nowrap"> <span class="text-foreground-default-secondary">Documents:</span> <span class="font-medium text-foreground">100</span> </div> <div class="h-3 w-px bg-background-default-tertiary-hover"></div> <div class="flex items-baseline gap-1 text-nowrap "> <span class="text-foreground-default-secondary">Price:</span> <span class="font-medium text-foreground">€0.00 / month</span> </div> </div> @popui.Menu(props.Menu{RightAlign: true}) { @popui.MenuItem() { @icons.Edit() <span>Edit</span> } @popui.MenuItem() { @icons.Delete() <span>Remove</span> } } </div> } @popui.Card(props.Card{Class: "flex-row items-center gap-1.5 p-3"}) { <div class="flex grow items-center gap-1.5"> @popui.Image(props.Image{ Src: "https://assets.invopop.com/apps/chargebee/icon.svg", Alt: "Chargebee", Class: "h-4 w-4 rounded-none", }) <span class="font-medium text-foreground">Chargebee</span> </div> <div class="flex items-center gap-4"> <div class="flex flex-wrap items-baseline gap-2 text-base justify-end"> <div class="flex items-baseline gap-1"> <span class="text-foreground-default-secondary">Seats:</span> <span class="font-medium text-foreground">10</span> </div> <div class="h-3 w-px bg-background-default-tertiary-hover"></div> <div class="flex items-baseline gap-1"> <span class="text-foreground-default-secondary">Price:</span> <span class="font-medium text-foreground">€0.00 / month</span> </div> </div> @popui.Menu(props.Menu{RightAlign: true}) { @popui.MenuItem() { @icons.Edit() <span>Edit</span> } @popui.MenuItem() { @icons.Delete() <span>Remove</span> } } </div> } } }

Address

Single-card variant containing a DescriptionList. The head pairs a label with a small secondary action button.

Address
Company legal name
Invopop S.L. Billing
Billing email
juan@invopop.com
Address
Calle Pradillo 42, Madrid Madrid, 28002, ES
Tax ID
ESX3157928M
123456789101112131415161718192021222324252627282930313233343536373839404142
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ CardDeckAddressExample() { @popui.CardDeck() { @popui.CardDeckHead() { <span>Address</span> @popui.Button(props.Button{Size: "sm"}) { Manage } } @popui.Card(props.Card{Class: "p-3"}) { @popui.DescriptionList(props.DescriptionList{Class: "w-full space-y-3"}) { @popui.DescriptionListItem(props.DescriptionListItem{ Label: "Company legal name", Value: "Invopop S.L. Billing", }) @popui.DescriptionListItem(props.DescriptionListItem{ Label: "Billing email", Value: "juan@invopop.com", }) @popui.DescriptionListItem() { @popui.DT() { Address } @popui.DD(props.DD{Class: "flex flex-col"}) { <span>Calle Pradillo 42, Madrid</span> <span>Madrid, 28002, ES</span> } } @popui.DescriptionListItem(props.DescriptionListItem{ Label: "Tax ID", Value: "ESX3157928M", }) } } } }

Payment Methods

Multi-card variant for stored payment methods. Each Card pairs a brand mark with the masked digits and inline meta. The first card carries a Default tag.

Payment
Visa· 3709
Exp 03/29Default
Mastercard· 8374
Exp 11/32
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ CardDeckPaymentExample() { @popui.CardDeck() { @popui.CardDeckHead() { <span>Payment</span> @popui.Button(props.Button{Size: "sm"}) { @icons.Add() <span>Add</span> } } @popui.Card(props.Card{Class: "flex-row items-center gap-1.5 p-3"}) { <div class="flex grow items-center gap-2"> @popui.Image(props.Image{ Src: "https://assets.invopop.com/payment-methods/visa.svg", Alt: "Visa", Class: "h-4 w-6 rounded-none object-contain", }) <span class="font-medium text-foreground">· 3709</span> </div> <div class="flex items-center gap-3"> <span class="text-base text-foreground-default-secondary">Exp 03/29</span> @popui.TagStatus(props.TagStatus{Label: "Default", Status: "grey"}) @popui.Menu(props.Menu{RightAlign: true}) { @popui.MenuItem() { @icons.Edit() <span>Edit</span> } @popui.MenuItem() { @icons.Delete() <span>Remove</span> } } </div> } @popui.Card(props.Card{Class: "flex-row items-center gap-1.5 p-3"}) { <div class="flex grow items-center gap-2"> @popui.Image(props.Image{ Src: "https://assets.invopop.com/payment-methods/mastercard.svg", Alt: "Mastercard", Class: "h-4 w-6 rounded-none object-contain", }) <span class="font-medium text-foreground">· 8374</span> </div> <div class="flex items-center gap-3"> <span class="text-base text-foreground-default-secondary">Exp 11/32</span> @popui.Menu(props.Menu{RightAlign: true}) { @popui.MenuItem() { @icons.Edit() <span>Edit</span> } @popui.MenuItem() { @icons.Delete() <span>Remove</span> } } </div> } } }

API Reference

CardDeck

Tinted container that stacks regular Card children into one visual unit, optionally led by a CardDeckHead. Child cards automatically get a smaller radius so their corners run concentric with the deck.

NameTypeDefaultDescription
ID string-Unique identifier for the deck element
Class string-Additional CSS classes to merge with deck styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)

CardDeckHead

Small muted header row for a CardDeck: a label on the left and any trailing content (a Button, a TagStatus) on the right.

NameTypeDefaultDescription
ID string-Unique identifier for the header element
Class string-Additional CSS classes to merge with header styles
Attributes templ.Attributes-Additional HTML attributes

Checkbox

Checkbox inputs with optional toggle switch variant.

12345678910111213
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ CheckboxExample() { @popui.Checkbox(props.Checkbox{ Name: "terms", Label: "I agree to the terms and conditions", }) }

Checked State

Checkbox can be pre-checked using the Checked prop.

1234567891011121314
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ CheckboxCheckedExample() { @popui.Checkbox(props.Checkbox{ Name: "newsletter", Label: "Subscribe to newsletter", Checked: true, }) }

With Description

Add a description below the label for additional context.

12345678910111213141516171819202122
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ CheckboxDescriptionExample() { <div class="space-y-4"> @popui.Checkbox(props.Checkbox{ Name: "marketing", Label: "Marketing communications", Description: "Receive emails about new products, features, and more.", }) @popui.Checkbox(props.Checkbox{ Name: "analytics", Label: "Usage analytics", Description: "Help us improve by sharing anonymous usage data.", Checked: true, }) </div> }

Switch Variant

Use Variant="switch" for a toggle switch style.

12345678910111213141516171819202122
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ CheckboxSwitchExample() { <div class="space-y-3"> @popui.Checkbox(props.Checkbox{ Name: "notifications", Label: "Enable notifications", Variant: props.CheckboxVariantSwitch, Checked: true, }) @popui.Checkbox(props.Checkbox{ Name: "marketing", Label: "Marketing emails", Variant: props.CheckboxVariantSwitch, }) </div> }

Switch with Description

Toggle switches can also include descriptions for additional context.

12345678910111213141516171819202122232425262728293031
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ CheckboxSwitchDescriptionExample() { <div class="space-y-3"> @popui.Checkbox(props.Checkbox{ Name: "notifications", Label: "Push notifications", Description: "Get notified about important updates and messages.", Variant: props.CheckboxVariantSwitch, Checked: true, }) @popui.Checkbox(props.Checkbox{ Name: "marketing", Label: "Marketing emails", Description: "Receive emails about new products and special offers.", Variant: props.CheckboxVariantSwitch, }) @popui.Checkbox(props.Checkbox{ Name: "analytics", Label: "Usage analytics", Description: "Help us improve by sharing anonymous usage data.", Variant: props.CheckboxVariantSwitch, Checked: true, }) </div> }

Disabled State

Disabled checkboxes and switches with reduced opacity.

12345678910111213141516171819202122232425262728
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ CheckboxDisabledExample() { <div class="space-y-3"> @popui.Checkbox(props.Checkbox{ Name: "option1", Label: "Disabled checkbox", Disabled: true, }) @popui.Checkbox(props.Checkbox{ Name: "option2", Label: "Disabled checked checkbox", Checked: true, Disabled: true, }) @popui.Checkbox(props.Checkbox{ Name: "option3", Label: "Disabled switch", Variant: props.CheckboxVariantSwitch, Disabled: true, }) </div> }

Option Group

Group multiple checkboxes together with a label.

1234567891011121314151617181920212223242526
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ CheckboxOptionGroupExample() { @popui.OptionGroup(props.OptionGroup{ Label: "Select your interests", }) { @popui.Checkbox(props.Checkbox{ Name: "interest_design", Label: "Design", Checked: true, }) @popui.Checkbox(props.Checkbox{ Name: "interest_development", Label: "Development", }) @popui.Checkbox(props.Checkbox{ Name: "interest_marketing", Label: "Marketing", }) } }

API Reference

Checkbox

Checkbox input with optional toggle switch variant.

NameTypeDefaultDescription
ID string-Unique identifier (auto-generated if not provided)
Class string-Additional CSS classes to merge with checkbox styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Label string-Label text for the checkbox
Description string-Optional description text displayed below the label
Variant string-Visual variant: "switch" for toggle switch style
Name string-Form field name
Value string-Form field value
Checked boolfalseWhether the checkbox is checked
Autofocus boolfalseWhether to autofocus on mount
Disabled boolfalseWhether the checkbox is disabled

OptionGroup

Groups form elements like checkboxes and radio buttons with a label.

NameTypeDefaultDescription
ID string-Unique identifier for the group element
Class string-Additional CSS classes to merge with group styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Label string-Label text for the group

DescriptionList

Semantic HTML definition list for displaying term-description pairs.

Name
John Doe
Role
Administrator
1234567891011121314151617181920212223242526272829
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ DescriptionListExample() { @popui.DescriptionList() { @popui.DescriptionListItem(props.DescriptionListItem{ Label: "Name", Value: "John Doe", }) @popui.DescriptionListItem(props.DescriptionListItem{ Label: "Email", }) { @popui.DD() { <a href="mailto:john@example.com">john@example.com</a> } } @popui.DescriptionListItem(props.DescriptionListItem{ Value: "Administrator", }) { @popui.DT() { Role } } } }

Custom Width

Override the default width to fit your layout.

Company
Acme Corporation
Address
123 Main Street, City, Country
123456789101112131415161718192021
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ DescriptionListCustomWidthExample() { @popui.DescriptionList(props.DescriptionList{ Class: "w-full", }) { @popui.DescriptionListItem(props.DescriptionListItem{ Label: "Company", Value: "Acme Corporation", }) @popui.DescriptionListItem(props.DescriptionListItem{ Label: "Address", Value: "123 Main Street, City, Country", }) } }

Rich Text Content

Use DT and DD components for complex HTML content.

Name
John Doe
Bio

Software engineer with expertise in Go and TypeScript.

  • 10+ years experience
  • Open source contributor
1234567891011121314151617181920212223242526272829
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ DescriptionListRichTextExample() { @popui.DescriptionList() { @popui.DescriptionListItem(props.DescriptionListItem{ Label: "Name", Value: "John Doe", }) @popui.DescriptionListItem() { @popui.DT() { Bio } @popui.DD() { @popui.Prose() { <p>Software engineer with expertise in <strong>Go</strong> and <strong>TypeScript</strong>.</p> <ul> <li>10+ years experience</li> <li>Open source contributor</li> </ul> } } } } }

Inline Rows & Actions

Inline lays the item out label-left / value-right. Actions add hover-revealed buttons (copy, external-link) next to the value, and PrefixLength / SuffixLength truncate long values (the full value is still copied). Leaving Inline unset stacks the label above the value while keeping the hover reveal.

Role
Director
Entry ID
ee42413c…ab20
Endpoint
0009:552100554
12345678910111213141516171819202122232425262728293031
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ DescriptionListActionsExample() { @popui.DescriptionList() { @popui.DescriptionListItem(props.DescriptionListItem{Inline: true, Label: "Role", Value: "Director"}) @popui.DescriptionListItem(props.DescriptionListItem{ Inline: true, Label: "Entry ID", Value: "ee42413c-79fc-42d0-a7f7-65f76990ab20", PrefixLength: 8, SuffixLength: 4, Actions: []props.DescriptionListAction{ {Icon: icons.Duplicate(), Copy: "ee42413c-79fc-42d0-a7f7-65f76990ab20", Attributes: templ.Attributes{"aria-label": "Copy"}}, {Icon: icons.ExternalLink(), URL: templ.SafeURL("https://app.invopop.com/silo-entry/ee42413c-79fc-42d0-a7f7-65f76990ab20"), Attributes: templ.Attributes{"aria-label": "Open in a new tab"}}, }, }) @popui.DescriptionListItem(props.DescriptionListItem{ Label: "Endpoint", Value: "0009:552100554", Actions: []props.DescriptionListAction{ {Icon: icons.Duplicate(), Copy: "0009:552100554", Attributes: templ.Attributes{"aria-label": "Copy"}}, }, }) } }

Detail View

A console-style side-panel detail view: section headings, inline rows with an em-dash for absent values, and a copyable mono id row.

Details

Role
Seller
Status
Registered
Country
ID
01980ffb…9d44

Inboxes

No inboxes

12345678910111213141516171819202122232425262728293031
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ DescriptionListDetailViewExample() { <div class="w-[360px]"> <h3 class="py-3 text-base font-medium text-foreground">Details</h3> @popui.DescriptionList(props.DescriptionList{Class: "w-full space-y-1 border-b border-border pb-4"}) { @popui.DescriptionListItem(props.DescriptionListItem{Inline: true, Label: "Role", Value: "Seller"}) @popui.DescriptionListItem(props.DescriptionListItem{Inline: true, Label: "Status", Value: "Registered"}) @popui.DescriptionListItem(props.DescriptionListItem{Inline: true, Label: "Country"}) @popui.DescriptionListItem(props.DescriptionListItem{ Inline: true, Mono: true, Label: "ID", Value: "01980ffb-94e1-7002-8f1d-3c5a2b7e9d44", PrefixLength: 8, SuffixLength: 4, Actions: []props.DescriptionListAction{ {Icon: icons.Duplicate(), Copy: "01980ffb-94e1-7002-8f1d-3c5a2b7e9d44", Attributes: templ.Attributes{"aria-label": "Copy"}}, }, }) } <h3 class="py-3 text-base font-medium text-foreground">Inboxes</h3> <p class="text-base text-foreground-default-secondary">No inboxes</p> </div> }

API Reference

DescriptionList

Container for definition list items (dl element).

NameTypeDefaultDescription
ID string-Unique identifier for the list element
Class string-Additional CSS classes to merge with list styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)

DescriptionListItem

Individual item with label and value, rendered as dt/dd pair.

NameTypeDefaultDescription
ID string-Unique identifier for the item element
Class string-Additional CSS classes to merge with item styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Label string-The term or label to display (dt element)
Value string-The description or value to display (dd element)
Inline boolfalseLay the item out label-left / value-right instead of the default stacked (label above value).
Mono boolfalseRender the value in the monospace face (ids, hashes).
PrefixLength int0Truncate the DISPLAYED value to prefix…suffix (the full value is still copied). 0 with SuffixLength 0 shows it untruncated.
SuffixLength int0Suffix length for prefix…suffix truncation; 0 renders prefix… only.
Actions []props.DescriptionListAction-Hover-revealed action buttons rendered next to the value, in order of placement.

DescriptionListAction

One hover-revealed action button on a DescriptionListItem's value. Provide an Icon plus a behavior: Copy (clipboard), URL (external link), or a plain button via Attributes.

NameTypeDefaultDescription
Icon templ.Component-Glyph rendered inside the button (e.g. icons.Duplicate(), icons.ExternalLink()).
Copy string-When set, the button copies this text to the clipboard.
URL templ.SafeURL-When set, the button is an anchor opening the URL in a new tab (target=_blank, rel=noopener noreferrer).
Attributes templ.Attributes-Extra attributes (aria-label, onclick, …); override the defaults a Copy / URL action sets.

DT

Definition term element (dt) with proper styling for use in DescriptionListItem.

NameTypeDefaultDescription
ID string-Unique identifier
Class string-Additional CSS classes
Attributes templ.Attributes-Additional HTML attributes

DD

Definition description element (dd) with proper styling for use in DescriptionListItem.

NameTypeDefaultDescription
ID string-Unique identifier
Class string-Additional CSS classes
Attributes templ.Attributes-Additional HTML attributes

Fieldset

Groups form fields together with proper spacing and optional legend.

123456789101112131415161718192021222324
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FieldsetExample() { @popui.Fieldset() { @popui.Input(props.Input{ ID: "email", Name: "email", Label: "Email", Placeholder: "Enter your email", }) @popui.Input(props.Input{ ID: "password", Name: "password", Type: "password", Label: "Password", Placeholder: "Enter your password", }) } }

With Legend

Add a legend to label the group of fields.

Account Information
12345678910111213141516171819202122232425
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FieldsetWithLegendExample() { @popui.Fieldset(props.Fieldset{ Legend: "Account Information", }) { @popui.Input(props.Input{ ID: "username", Name: "username", Label: "Username", Placeholder: "Choose a username", }) @popui.Input(props.Input{ ID: "email2", Name: "email", Label: "Email", Placeholder: "your@email.com", }) } }

Card Variant

The card variant wraps the fields in a bordered container with a light gray background. Use it for settings sections and grouped form blocks.

Profile Settings
1234567891011121314151617181920212223242526
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FieldsetCardStyleExample() { @popui.Fieldset(props.Fieldset{ Legend: "Profile Settings", Variant: props.FieldsetVariantCard, }) { @popui.Input(props.Input{ ID: "name", Name: "name", Label: "Full Name", Placeholder: "John Doe", }) @popui.Textarea(props.Textarea{ ID: "bio", Name: "bio", Label: "Bio", Placeholder: "Tell us about yourself", }) } }

Card with Select

Any field works inside the card variant — here a multi-select.

Categories
12345678910111213141516171819202122232425
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FieldsetCardExample() { @popui.Fieldset(props.Fieldset{ Legend: "Categories", Variant: props.FieldsetVariantCard, }) { @popui.Select(props.Select{ Multiple: true, Name: "categories", Placeholder: "Select categories", Options: []props.SelectOption{ {Value: "document", Label: "Document", Selected: true}, {Value: "accounting", Label: "Accounting"}, {Value: "payments", Label: "Payments"}, {Value: "tax", Label: "Tax"}, }, }.GenerateID()) } }

Card with Form Grid

Wrap fields in a grid to lay them out in multiple columns inside the card variant.

URLs
12345678910111213141516171819202122232425262728293031323334353637383940
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FieldsetCardFormExample() { @popui.Fieldset(props.Fieldset{ Legend: "URLs", Variant: props.FieldsetVariantCard, }) { <div class="grid grid-cols-2 gap-4"> @popui.Input(props.Input{ ID: "config-url", Name: "config_url", Label: "Config URL", Placeholder: "https://", }) @popui.Input(props.Input{ ID: "launch-url", Name: "launch_url", Label: "Launch URL", Placeholder: "https://", }) @popui.Input(props.Input{ ID: "info-url", Name: "info_url", Label: "Info URL", Placeholder: "https://", }) @popui.Input(props.Input{ ID: "api-url", Name: "api_url", Label: "API URL", Placeholder: "https://", }) </div> } }

Titled Section

Pair a TitleGroup with the card variant for a titled settings section: the heading sits outside the tinted body.

Categories · Select all that apply
1234567891011121314151617181920212223242526272829
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FieldsetTitledExample() { <div class="w-full flex flex-col gap-3"> @popui.TitleGroup(props.TitleGroup{ Title: "Categories", Description: "Select all that apply", Horizontal: true, }) @popui.Fieldset(props.Fieldset{Variant: props.FieldsetVariantCard}) { @popui.Select(props.Select{ Multiple: true, Name: "categories", Placeholder: "Select categories", Options: []props.SelectOption{ {Value: "document", Label: "Document", Selected: true}, {Value: "accounting", Label: "Accounting"}, {Value: "payments", Label: "Payments"}, {Value: "tax", Label: "Tax"}, }, }.GenerateID()) } </div> }

API Reference

Fieldset

Groups form fields together with proper spacing and optional legend.

NameTypeDefaultDescription
ID string-Unique identifier for the fieldset element
Class string-Additional CSS classes to merge with fieldset styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Legend string-Text to display as the fieldset legend
Variant string-Visual variant: "card" for a bordered container with a light gray background

File

File components for selecting, uploading and displaying files. Use InputFile for basic file selection, FileUpload for avatar/image uploads with preview, and FileDownload for displaying stored files.

123456789101112
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FileExample() { @popui.InputFile(props.InputFile{ Name: "document", }) }

Disabled State

Disabled file inputs prevent user interaction.

12345678910111213
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FileDisabledExample() { @popui.InputFile(props.InputFile{ Name: "document", Disabled: true, }) }

Accept Specific Types

Restrict file selection to specific file types using the Accept prop.

12345678910111213141516171819
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FileAcceptTypesExample() { <div class="space-y-4"> @popui.InputFile(props.InputFile{ Name: "images", Accept: "image/*", }) @popui.InputFile(props.InputFile{ Name: "documents", Accept: ".pdf,.doc,.docx", }) </div> }

Multiple Files

Allow multiple file selection with the Multiple prop.

1234567891011121314
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FileMultipleExample() { @popui.InputFile(props.InputFile{ Name: "photos", Multiple: true, Accept: "image/*", }) }

Upload Without Preview

FileUpload without an initial avatar shows a placeholder icon.

Upload Profile Picture
12345678910111213
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FileUploadNoPreviewExample() { @popui.FileUpload(props.InputFile{ Name: "profile-picture", Text: "Upload Profile Picture", }) }

Avatar Upload

Use FileUpload for file inputs with avatar preview.

User Avatar Change Avatar
123456789101112131415
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FileAvatarExample() { @popui.FileUpload(props.InputFile{ Name: "avatar", AvatarURL: "https://api.dicebear.com/7.x/avataaars/svg?seed=Felix", AvatarAlt: "User Avatar", Text: "Change Avatar", }) }

Square Preview

Use PreviewSquare for square avatar previews (useful for logos).

Company Logo Upload Logo
12345678910111213141516
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FileSquarePreviewExample() { @popui.FileUpload(props.InputFile{ Name: "logo", AvatarURL: "https://api.dicebear.com/7.x/shapes/svg?seed=Logo", AvatarAlt: "Company Logo", Text: "Upload Logo", PreviewSquare: true, }) }

With Additional Buttons

Pass children to add extra buttons like Remove or Cancel.

User Avatar Change Avatar
12345678910111213141516171819202122
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FileWithButtonsExample() { @popui.FileUpload(props.InputFile{ Name: "avatar", AvatarURL: "https://api.dicebear.com/7.x/avataaars/svg?seed=Felix", AvatarAlt: "User Avatar", Text: "Change Avatar", }) { @popui.Button(props.Button{ Type: "button", Size: "sm", }) { Remove } } }

File Download

FileDownload displays a stored file with its info and actions. Expects FileDownloadInfo and action buttons as children.

PNG

dni_back_already_stored.png

Download
123456789101112131415161718192021222324252627282930
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FileDownloadExample() { @popui.FileDownload() { @popui.FileDownloadInfo(props.FileDownloadInfo{ Label: "dni_back_already_stored.png", }) { @popui.Avatar(props.Avatar{ Initial: "PNG", Color: "document-png", Size: props.AvatarSizeLarge, Class: "rounded-md font-mono", }) } @popui.Button(props.Button{ Variant: "transparent", Href: "#", Download: true, }) { @icons.Download() Download } } }

Borderless File Download

FileDownload can render without a border and highlight the row via the Hover prop. FileDownloadInfo accepts a Value shown as muted text below the label.

XML

invoice.xml

Jul 14, 2026 at 04:14 PM · 3 KB

Download

invoice.xml

The preview content is managed by the app implementing this component: the Preview prop only wires the row's click to your own function, which decides what to display.

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FileDownloadBorderlessExample() { @popui.FileDownload(props.FileDownload{ Borderless: true, Hover: true, Preview: props.ShowPopover("file-download-preview"), }) { @popui.FileDownloadInfo(props.FileDownloadInfo{ Label: "invoice.xml", Value: "Jul 14, 2026 at 04:14 PM · 3 KB", }) { @popui.Avatar(props.Avatar{ Initial: "XML", Color: "document-xml", Size: props.AvatarSizeLarge, Class: "rounded-md font-mono", }) } @popui.Button(props.Button{ Variant: "transparent", Href: "#", Download: true, }) { @icons.Download() Download } } @popui.Popover(props.Popover{ ID: "file-download-preview", }) { @popui.Block() { @popui.Title() { invoice.xml } @popui.P() { The preview content is managed by the app implementing this component: the Preview prop only wires the row's click to your own function, which decides what to display. } @popui.ButtonGroup(props.ButtonGroup{Align: "right"}) { @popui.Button(props.Button{ Variant: props.ButtonVariantSecondary, PopoverTarget: "file-download-preview", PopoverTargetAction: "hide", }) { Close } } } } }

API Reference

InputFile

Basic file input component.

NameTypeDefaultDescription
ID stringauto-generatedUnique identifier for the file input
Class string-Additional CSS classes
Attributes templ.Attributes-Additional HTML attributes
Name string-Name attribute for form submission
Accept string-Accepted file types (e.g., "image/*", ".pdf,.doc")
Capture string-Capture media from device camera ("user" or "environment")
Multiple boolfalseAllow multiple file selection
Autofocus boolfalseAutofocus the file input on page load
Required boolfalseMake the file input required
Disabled boolfalseDisable the file input

FileUpload

File upload component with avatar preview.

NameTypeDefaultDescription
ID stringauto-generatedUnique identifier for the file upload
Class string-Additional CSS classes
Attributes templ.Attributes-Additional HTML attributes
Name string-Name attribute for form submission
Accept string-Accepted file types
Capture string-Capture media from device camera ("user" or "environment")
Required boolfalseMake the file upload required
Disabled boolfalseDisable the file upload
Multiple boolfalseAllow multiple file selection
AvatarURL string-Avatar image URL for preview
AvatarAlt string-Alt text for avatar image
Text string-Text label before upload button
PreviewSquare boolfalseUse square preview instead of circle

FileDownload

Displays a stored file with its info and actions. Expects FileDownloadInfo and action buttons as children.

NameTypeDefaultDescription
ID string-Unique identifier for the file element
Class string-Additional CSS classes to merge with file styles
Attributes templ.Attributes-Additional HTML attributes
Borderless boolfalseRemoves the border for embedding the file row inside another container
Hover boolfalseHighlights the whole row with a background color on hover
Preview string-JavaScript expression run when the row is clicked, e.g. props.ShowPopover(id)

FileDownloadInfo

Structured layout for file information within FileDownload (icon, name, etc.).

NameTypeDefaultDescription
ID string-Unique identifier for the file info element
Class string-Additional CSS classes to merge with file info styles
Attributes templ.Attributes-Additional HTML attributes
Label string-File name or label text to display
Value string-Smaller, muted text rendered below the label (e.g. timestamp or file size)

Filter

Search-bar style filter for data views: a "+ Filter" menu plus one editable chip per active filter, with multi-field filtering, colored option lists, and keyboard navigation.

Status
is any of
Select status… Active Pending Archived
Priority
matches
Select priority… High Normal Low
Customer
matches
Created Date
is between
Select created date…
1234567891011121314151617181920212223242526272829303132333435363738394041
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FilterExample() { @popui.Filter(props.Filter{ BaseURL: "/data", Target: "#table-body", PageSize: 20, Inputs: []props.FilterInput{ { Name: "doc_status", Label: "Status", Icon: icons.Status(), Type: props.FilterTypeMultiple, Options: []props.FilterOption{ {Value: "active", Label: "Active", Color: "green"}, {Value: "pending", Label: "Pending", Color: "orange"}, {Value: "archived", Label: "Archived", Color: "grey"}, }, }, { Name: "priority_level", Label: "Priority", Icon: icons.Tag(), Type: props.FilterTypeSelect, Options: []props.FilterOption{ {Value: "high", Label: "High", Color: "red"}, {Value: "normal", Label: "Normal", Color: "blue"}, {Value: "low", Label: "Low", Color: "grey"}, }, }, {Name: "customer_name", Label: "Customer", Icon: icons.Search(), Type: props.FilterTypeText}, {Name: "created_at", Label: "Created Date", Icon: icons.Calendar(), Type: props.FilterTypeCalendar}, }, }) }

API Reference

Filter

Filter renders a search bar style filter row with a Filter menu and one editable chip for each active field. All active filters apply together on every submission.

NameTypeDefaultDescription
ID string-Sets the unique identifier of the form element.
Class string-Adds CSS classes that are merged with the base styling of the row.
Attributes templ.Attributes-Applies additional HTML attributes to the form element.
BaseURL string-Defines the URL the form submits to through hx-get. The active filter values are serialised as query parameters.
Target string-Selects the region that is swapped when the filters change. Point it at the data region so the filter row itself survives each submission.
Select stringTargetChooses the fragment of the response to swap in through hx-select. It defaults to the same region as Target.
Swap stringouterHTMLControls the HTMX swap mode. It defaults to outerHTML so the region element is replaced whole.
PageSize int0Adds a hidden size input with this value to every submission. A value of zero omits the input.
Inputs []FilterInput-Declares the filterable fields. Each field renders one chip while it is active.

FilterInput

FilterInput describes one filterable field. The Type field picks which value editor the chip shows.

NameTypeDefaultDescription
Name string-Sets the query parameter key the field submits under.
Label string-Provides the text shown in the Filter menu and on the chip.
Type stringtextSelects the value editor. Valid values are text, select, multiple and calendar.
PluralLabel string-Overrides the pluralised label the multiple editor shows in its summary. Set it for irregular plurals.
Icon templ.Component-Provides the icon shown in the Filter menu and on the chip.
Values []string-Seeds the values that are already applied, usually parsed from the URL. A field with values renders as an active chip.
Options []FilterOption-Lists the choices available to the select and multiple editors.
Presets []props.CalendarPresetdefaultConfigures the preset rail shown by the calendar editor. It defaults to the standard presets.

FilterOption

FilterOption is one choice offered by a select or multiple editor.

NameTypeDefaultDescription
Value string-Sets the value submitted when the option is selected.
Label string-Provides the text displayed for the option.
Color string-Applies a TagStatus color and renders a matching dot next to the label.

Form

Form element with proper spacing and standard HTML form attributes for handling submissions.

1234567891011121314151617181920212223242526272829303132333435
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FormExample() { @popui.Form(props.Form{ Action: "/submit", Method: "POST", }) { @popui.Input(props.Input{ ID: "email", Name: "email", Label: "Email", Placeholder: "Enter your email", }) @popui.Input(props.Input{ ID: "password", Name: "password", Type: "password", Label: "Password", Placeholder: "Enter your password", }) @popui.ButtonGroup() { @popui.Button(props.Button{ Type: "submit", Variant: props.ButtonVariantPrimary, }) { Submit } } } }

File Upload Form

Form with multipart encoding for file uploads.

123456789101112131415161718192021222324252627282930313233
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ FormFileUploadExample() { @popui.Form(props.Form{ Action: "/upload", Method: "POST", Enctype: "multipart/form-data", }) { @popui.Input(props.Input{ ID: "title", Name: "title", Label: "Document Title", Placeholder: "Enter document title", }) @popui.InputFile(props.InputFile{ ID: "document", Name: "document", Text: "Upload File", }) @popui.ButtonGroup() { @popui.Button(props.Button{ Type: "submit", }) { Upload Document } } } }

API Reference

Form

Groups form fields together with proper spacing and handles form submission.

NameTypeDefaultDescription
ID string-Unique identifier for the form element
Class string-Additional CSS classes to merge with form styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Variant string-Visual variant: "card" for bordered card style
Action string-URL where form data will be submitted
Method string-HTTP method to use (GET, POST, etc.)
Enctype string-Encoding type for form data (e.g., "multipart/form-data")
Target string-Where to display response (_self, _blank, etc.)
Autocomplete string-Whether form should have autocomplete on or off
Novalidate boolfalseDisable form validation when true
AcceptCharset string-Character encodings for form submission
Name string-Name of the form
Rel string-Relationship between current and linked document

Image

Displays images with rounded corners and proper object fit.

1234567891011121314
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ ImageExample() { <div class="w-32 h-32"> @popui.Image(props.Image{ Src: "https://i.pravatar.cc/300?img=1", }) </div> }

Custom Size

Use custom classes to control image dimensions and object fit.

Product image
1234567891011121314
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ ImageCustomSizeExample() { @popui.Image(props.Image{ Src: "https://i.pravatar.cc/300?img=5", Alt: "Product image", Class: "w-40 h-24 object-contain", }) }

With Avatar

Wrap Image inside Avatar component for circular avatars.

User avatar
User avatar
1234567891011121314151617181920212223
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ ImageWithAvatarExample() { <div class="flex gap-4"> @popui.Avatar(props.Avatar{Size: "lg"}) { @popui.Image(props.Image{ Src: "https://i.pravatar.cc/150?img=8", Alt: "User avatar", }) } @popui.Avatar() { @popui.Image(props.Image{ Src: "https://i.pravatar.cc/150?img=12", Alt: "User avatar", }) } </div> }

Country Flags

Country flags come from the Invopop assets CDN: https://assets.invopop.com/flags/<cc>.svg, where <cc> is the lowercase ISO 3166-1 alpha-2 country code.

esusgbfrdeitmx
123456789101112131415161718
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ ImageFlagsExample() { <div class="flex items-center gap-3"> for _, cc := range []string{"es", "us", "gb", "fr", "de", "it", "mx"} { @popui.Image(props.Image{ Src: "https://assets.invopop.com/flags/" + cc + ".svg", Alt: cc, Class: "w-5 h-3.5 rounded-[1.5px]", }) } </div> }

API Reference

Image

Displays an image with rounded corners and proper object fit.

NameTypeDefaultDescription
ID string-Unique identifier for the image element
Class string-Additional CSS classes to merge with image styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Src string-Image source URL
Alt string-Alternative text for accessibility

Input

Text input field for capturing user data with various types and validation.

1234567891011121314151617181920212223
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ InputExample() { @popui.Input(props.Input{ ID: "name-size-default", Placeholder: "Enter your name", }) @popui.Input(props.Input{ ID: "name-size-small", Size: props.InputSizeSmall, Placeholder: "Enter your name (small)", }) @popui.Input(props.Input{ ID: "name-size-large", Size: props.InputSizeLarge, Placeholder: "Enter your name (large)", }) }

Input Types

Input supports various types including text, email, password, date, and more.

1234567891011121314151617181920
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ InputTypesExample() { @popui.Input(props.Input{ Type: "email", Placeholder: "email@example.com", }) @popui.Input(props.Input{ Type: "password", Placeholder: "Enter password", }) @popui.Input(props.Input{ Type: "date", }) }

With Label

Use the Label prop for a simple text label above the input.

123456789101112131415
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ InputWithLabelExample() { @popui.Input(props.Input{ ID: "email-with-label", Label: "Email", Type: "email", Placeholder: "email@example.com", }) }

Custom Label

For advanced label features like hints, render a Label component separately with proper spacing using a flex container.

12345678910111213141516171819
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ InputCustomLabelExample() { <div class="flex flex-col space-y-2 w-full"> @popui.Label(props.Label{ID: "username", Hint: "Choose a unique username"}) { Username } @popui.Input(props.Input{ ID: "custom-username", Type: "text", Placeholder: "johndoe", }) </div> }

Disabled & Read-only

Input can be disabled to prevent interaction or set to read-only to prevent editing.

1234567891011121314151617
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ InputDisabledExample() { @popui.Input(props.Input{ Placeholder: "This input is disabled", Disabled: true, }) @popui.Input(props.Input{ Value: "Read-only value", Readonly: true, }) }

With Error

Input can display error messages for validation feedback.

Please enter a valid email address

1234567891011121314151617181920
package examples import ( "errors" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ InputWithErrorExample() { @popui.Input(props.Input{ ID: "email-with-error", Label: "Email", Type: "email", Placeholder: "email@example.com", Value: "invalid-email", Error: props.Error{ Error: errors.New("Please enter a valid email address"), }, }) }

With Dynamic Error

Input can display dynamic error messages for validation feedback when using frameworks like Alpine.js.

123456789101112131415161718192021222324252627282930313233343536
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/classes" "github.com/invopop/popui.go/props" ) templ InputWithDynamicErrorExample() { <div x-data={ ` { email: 'bad@email.com', errors: { email: "Invalid email address" } } ` } > @popui.Input(props.Input{ ID: "email-with-dynamic-error", Label: "Email", Type: "email", Placeholder: "email@example.com", Attributes: templ.Attributes{ "x-model": "email", ":class": "{ '" + classes.FormFieldError() + "': errors.email }", }, Error: props.Error{ Attributes: templ.Attributes{ "x-text": "errors.email", }, }, }) </div> }

With Icon

Input can include an icon inside the input field using the Icon prop.

123456789101112131415161718192021222324252627282930313233
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ InputWithIconExample() { @popui.Input(props.Input{ ID: "email-with-icon", Label: "Email", Type: "email", Placeholder: "email@example.com", Icon: icons.Envelope(), }) @popui.Input(props.Input{ ID: "email-with-icon-small", Size: props.InputSizeSmall, Label: "Email (Small)", Type: "email", Placeholder: "email@example.com", Icon: icons.Envelope(), }) @popui.Input(props.Input{ ID: "email-with-icon-large", Size: props.InputSizeLarge, Label: "Email (Large)", Type: "email", Placeholder: "email@example.com", Icon: icons.Envelope(), }) }

API Reference

Input

Text input field with support for various types and validation.

NameTypeDefaultDescription
ID string-Unique identifier for the input element
Class string-Additional CSS classes to merge with input styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Type stringtextInput type: text, email, password, tel, url, date, time, week, month, search, file
Placeholder string-Placeholder text displayed when input is empty
Value string-Initial or current value of the input
Name string-Name attribute for form submission
Label string-Simple label text displayed above the input
Prefix string-Text or symbol displayed before the input field
Autofocus boolfalseAutomatically focuses the input on page load
Disabled boolfalseDisables the input
Readonly boolfalseMakes the input read-only
Required boolfalseMarks the input as required for form validation
Error props.Error-Error configuration to display validation feedback below the input

Error

Error configuration for displaying validation feedback.

NameTypeDefaultDescription
Error error-Go error object to display (calls .Error() method)
Text string-Text string to display as error message
Class string-Additional CSS classes to merge with error styles
Attributes templ.Attributes-Additional HTML attributes for the error element

Label

Form label element with optional hint tooltip.

123456789101112
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ LabelExample() { @popui.Label(props.Label{ID: "label-username"}) { Username } }

With Hint

Add a hint tooltip with the Hint prop. A question mark icon will appear that shows the hint on hover.

123456789101112131415
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ LabelWithHintExample() { @popui.Label(props.Label{ ID: "email-with-hint", Hint: "This will be your primary contact email", }) { Email Address } }

Custom Styling

Use the Class prop to customize the label appearance with Tailwind classes.

123456789101112131415
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ LabelCustomStyleExample() { @popui.Label(props.Label{ ID: "custom-password", Class: "text-foreground-accent text-base font-semibold", }) { Password } }

Usage

The Label component is used in:

API Reference

Label

Form label element with optional hint tooltip.

NameTypeDefaultDescription
ID string-ID of the input element this label is for (sets the 'for' attribute)
Class string-Additional CSS classes to merge with label styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Hint string-Tooltip text shown on hover via a question mark icon

Menu

A dropdown menu of actions that opens from a trigger button.

1234567891011121314151617
package examples import "github.com/invopop/popui.go" templ MenuExample() { @popui.Menu() { @popui.MenuItem() { Edit } @popui.MenuItem() { Duplicate } @popui.MenuItem() { Delete } } }

Right Aligned

Align the menu to the right side of the button

123456789101112131415161718192021222324
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ MenuRightAlignedExample() { @popui.Menu(props.Menu{ ID: "context-menu-right", ButtonLabel: "···", RightAlign: true, }) { @popui.MenuItem() { Settings } @popui.MenuItem() { Profile } @popui.MenuItem() { Logout } } }

Custom Trigger

Set Trigger to open the menu from any component — an avatar, an icon, a styled row — instead of the default kebab button. The trigger content is wrapped in an unstyled button carrying the popover wiring, so pass non-interactive content.

1234567891011121314151617181920212223242526272829
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ MenuCustomTriggerExample() { @popui.Menu(props.Menu{ Trigger: menuAvatarTrigger(), }) { @popui.MenuItem() { Profile } @popui.MenuItem() { Switch workspace } @popui.MenuItem() { Log out } } } templ menuAvatarTrigger() { <span class="inline-flex items-center gap-2"> @popui.Avatar(props.Avatar{Initial: "JD", Color: "accent", Size: props.AvatarSizeLarge}) <span class="text-base font-medium text-foreground">John Doe</span> </span> }

API Reference

Menu

The main menu component that displays a menu.

NameTypeDefaultDescription
ID string-Optional identifier for the container. If not provided, Alpine.js x-id generates unique IDs automatically for each instance
Class string-Additional CSS classes to merge with base styles
Attributes templ.Attributes-Additional HTML attributes to apply to the menu container
ButtonLabel string-Text label for the trigger button
ButtonVariant string-Variant style for the trigger button (e.g., 'primary', 'secondary', 'transparent')
Trigger templ.Component-Replaces the default button with any component as the menu opener. ButtonLabel and ButtonVariant are ignored when set
RightAlign boolfalseAlign the menu to the right side of the button

MenuItem

Individual menu item within the menu.

NameTypeDefaultDescription
ID string-Unique identifier for the item element
Class string-Additional CSS classes to merge with base styles
Attributes templ.Attributes-Additional HTML attributes to apply to the list item

Notification

Feedback messages with different severity types and icons.

Info

New feature available

Check out the new reporting dashboard in your settings.

1234567891011121314
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ NotificationInfoExample() { @popui.Notification(props.Notification{ Type: "info", Text: "New feature available", Description: "Check out the new reporting dashboard in your settings.", }) }

Warning

Action required

Your payment method will expire soon. Please update it.

1234567891011121314
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ NotificationWarningExample() { @popui.Notification(props.Notification{ Type: "warning", Text: "Action required", Description: "Your payment method will expire soon. Please update it.", }) }

Error

Upload failed

The file size exceeds the maximum allowed limit.

1234567891011121314
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ NotificationErrorExample() { @popui.Notification(props.Notification{ Type: "error", Text: "Upload failed", Description: "The file size exceeds the maximum allowed limit.", }) }

Success

Changes saved

Your profile has been updated successfully.

1234567891011121314
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ NotificationSuccessExample() { @popui.Notification(props.Notification{ Type: "success", Text: "Changes saved", Description: "Your profile has been updated successfully.", }) }

API Reference

Notification

Feedback message component with different severity types.

NameTypeDefaultDescription
ID string-Unique identifier for the notification element
Class string-Additional CSS classes to merge with notification styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Type string-Notification type: info, warning, error, or success
Text string-Main notification text (bold)
Description string-Additional descriptive text

PageState

Layout for displaying page states with illustrations and call-to-action.

No results found

Try adjusting your search or filter to find what you're looking for.

123456789101112131415161718
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ PageStateExample() { @popui.PageState(props.PageState{ Illustration: popui.EmptyStateIcon(), Title: "No results found", Description: "Try adjusting your search or filter to find what you're looking for.", }) { @popui.Button(props.Button{Variant: "primary"}) { Clear filters } } }

API Reference

PageState

Layout component for displaying page states with optional call-to-action.

NameTypeDefaultDescription
ID string-Unique identifier for the page state element
Class string-Additional CSS classes to merge with page state styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Illustration templ.Component-SVG or component to display as the illustration for the page state
Title string-Title text displayed prominently in the page state
Description string-Descriptive text providing context about the page state

Popover

A centered modal dialog using the HTML popover API with backdrop overlay.

Modal Title

This is a centered modal popover using the HTML popover API. It displays content in the center of the screen with a backdrop overlay.

123456789101112131415161718192021222324252627282930313233343536
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ PopoverExample() { @popui.Button(props.Button{ PopoverTarget: "example-popover", }) { Open Modal } @popui.Popover(props.Popover{ ID: "example-popover", }) { @popui.Block() { @popui.Title() { Modal Title } @popui.P() { This is a centered modal popover using the HTML popover API. It displays content in the center of the screen with a backdrop overlay. } @popui.ButtonGroup(props.ButtonGroup{Align: "right"}) { @popui.Button(props.Button{ Variant: props.ButtonVariantSecondary, PopoverTarget: "example-popover", PopoverTargetAction: "hide", }) { Close } } } } }

API Reference

Popover

A centered modal dialog that uses the HTML popover API. The popover can be triggered by any element using the popovertarget attribute.

NameTypeDefaultDescription
ID *string-Unique identifier for the popover element
Class string-Additional CSS classes to merge with base styles
Attributes templ.Attributes-Additional HTML attributes to apply to the popover container

Radio

Radio button inputs for selecting a single option from a group.

1234567891011121314
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ RadioExample() { @popui.Radio(props.Radio{ Name: "plan", Value: "basic", Label: "Basic Plan", }) }

Checked State

Radio can be pre-checked using the Checked prop.

12345678910111213141516171819202122
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ RadioCheckedExample() { <div class="space-y-3"> @popui.Radio(props.Radio{ Name: "subscription", Value: "basic", Label: "Basic Plan", }) @popui.Radio(props.Radio{ Name: "subscription", Value: "pro", Label: "Pro Plan", Checked: true, }) </div> }

Disabled State

Disabled radio buttons with reduced opacity.

123456789101112131415161718192021222324
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ RadioDisabledExample() { <div class="space-y-3"> @popui.Radio(props.Radio{ Name: "option", Value: "1", Label: "Disabled radio", Disabled: true, }) @popui.Radio(props.Radio{ Name: "option", Value: "2", Label: "Disabled checked radio", Checked: true, Disabled: true, }) </div> }

With Description

Add a description below the label for additional context.

1234567891011121314151617181920212223242526272829303132
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ RadioWithDescriptionExample() { @popui.OptionGroup(props.OptionGroup{ Label: "Select your subscription", }) { @popui.Radio(props.Radio{ Name: "subscription", Value: "free", Label: "Free", Description: "Perfect for personal projects and testing.", Checked: true, }) @popui.Radio(props.Radio{ Name: "subscription", Value: "pro", Label: "Pro - $9/month", Description: "Best for professionals and small teams.", }) @popui.Radio(props.Radio{ Name: "subscription", Value: "enterprise", Label: "Enterprise", Description: "Custom pricing for large organizations.", }) } }

Option Group

Group multiple radio buttons together with a label.

1234567891011121314151617181920212223242526272829
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ RadioOptionGroupExample() { @popui.OptionGroup(props.OptionGroup{ Label: "Choose your plan", }) { @popui.Radio(props.Radio{ Name: "plan", Value: "free", Label: "Free", Checked: true, }) @popui.Radio(props.Radio{ Name: "plan", Value: "pro", Label: "Pro - $9/month", }) @popui.Radio(props.Radio{ Name: "plan", Value: "enterprise", Label: "Enterprise - Contact us", }) } }

Card Variant

Card-style radio buttons with descriptions, perfect for selection groups that need more context.

123456789101112131415161718192021222324252627282930313233
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ RadioCardExample() { <div class="space-y-3"> @popui.Radio(props.Radio{ Name: "plan-card", Value: "starter", Label: "Starter", Description: "Perfect for individuals and small projects.", Variant: "card", Checked: true, }) @popui.Radio(props.Radio{ Name: "plan-card", Value: "professional", Label: "Professional", Description: "Best for growing teams and businesses.", Variant: "card", }) @popui.Radio(props.Radio{ Name: "plan-card", Value: "enterprise", Label: "Enterprise", Description: "Custom solutions for large organizations.", Variant: "card", }) </div> }

Theme Variant

Circular color theme selector buttons. Use theme color constants (ColorSherwood, ColorOcean, ColorGrape, ColorMetal, ColorCosmos) as the Variant value.

12345678910111213141516171819202122232425262728293031323334353637
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ RadioThemeExample() { <div class="flex gap-3"> @popui.Radio(props.Radio{ Name: "color-theme", Value: "sherwood", Variant: props.ColorSherwood, Checked: true, }) @popui.Radio(props.Radio{ Name: "color-theme", Value: "ocean", Variant: props.ColorOcean, }) @popui.Radio(props.Radio{ Name: "color-theme", Value: "grape", Variant: props.ColorGrape, }) @popui.Radio(props.Radio{ Name: "color-theme", Value: "metal", Variant: props.ColorMetal, }) @popui.Radio(props.Radio{ Name: "color-theme", Value: "cosmos", Variant: props.ColorCosmos, }) </div> }

API Reference

Radio

Radio button input component.

NameTypeDefaultDescription
ID stringauto-generatedUnique identifier for the radio input
Class string-Additional CSS classes
Attributes templ.Attributes-Additional HTML attributes
Label string-Label text for the radio button
Description string-Optional description text shown below the label
Name string-Name attribute for form submission
Value string-Value of the radio button
Variant string-Style variant: "card" for card-style radios, or theme colors (props.ColorSherwood, props.ColorOcean, props.ColorGrape, props.ColorMetal, props.ColorCosmos)
Checked boolfalsePre-check the radio button
Autofocus boolfalseAutofocus the radio button on page load
Disabled boolfalseDisable the radio button

Select

Dropdown selection control for choosing one or more options from a list.

123456789101112131415161718
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SelectExample() { @popui.Select(props.Select{ Name: "country", }) { <option value="">Choose a country</option> <option value="es">Spain</option> <option value="fr">France</option> <option value="de">Germany</option> <option value="it">Italy</option> } }

With Options

Options can be defined in the props.Select Options field instead of using child option elements. This is useful for dynamic option generation.

12345678910111213141516171819202122
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SelectWithOptionsExample() { @popui.Select(props.Select{ ID: "country-with-options", Name: "country", Label: "Country", Options: []props.SelectOption{ {Value: "", Label: "Choose a country"}, {Value: "es", Label: "Spain", Selected: true}, {Value: "fr", Label: "France"}, {Value: "de", Label: "Germany"}, {Value: "it", Label: "Italy"}, {Value: "pt", Label: "Portugal", Disabled: true}, }, }) }

With Label

Use the Label prop for a simple text label above the select.

12345678910111213141516171819
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SelectWithLabelExample() { @popui.Select(props.Select{ ID: "country-with-label", Name: "country", Label: "Country", }) { <option value="">Choose a country</option> <option value="es">Spain</option> <option value="fr">France</option> <option value="de">Germany</option> } }

Custom Label

For advanced label features like hints, render a Label component separately with proper spacing using a flex container.

1234567891011121314151617181920212223242526
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SelectCustomLabelExample() { <div class="flex flex-col space-y-2"> @popui.Label(props.Label{ ID: "custom-country", Hint: "Choose your preferred country", }) { Country } @popui.Select(props.Select{ ID: "custom-country", Name: "country", }) { <option value="">Select a country</option> <option value="es">Spain</option> <option value="fr">France</option> <option value="de">Germany</option> } </div> }

Disabled

Select can be disabled to prevent user interaction.

1234567891011121314151617
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SelectDisabledExample() { @popui.Select(props.Select{ Name: "country", Disabled: true, }) { <option value="es" selected>Spain</option> <option value="fr">France</option> <option value="de">Germany</option> } }

With Error

Select can display error messages for validation feedback.

Please select a country

1234567891011121314151617181920212223
package examples import ( "errors" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SelectWithErrorExample() { @popui.Select(props.Select{ ID: "country-with-error", Name: "country", Label: "Country", Error: props.Error{ Error: errors.New("Please select a country"), }, }) { <option value="">Choose a country</option> <option value="es">Spain</option> <option value="fr">France</option> <option value="de">Germany</option> } }

Multiple

Set Multiple to select any number of options, shown as removable tag chips inside the field. Each value is submitted under Name via a hidden native select, and the field is fully keyboard operable.

12345678910111213141516171819202122
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SelectMultipleExample() { @popui.Select(props.Select{ Multiple: true, Name: "countries", Placeholder: "Choose countries", Options: []props.SelectOption{ {Value: "es", Label: "Spain", Selected: true}, {Value: "fr", Label: "France", Selected: true}, {Value: "de", Label: "Germany"}, {Value: "it", Label: "Italy"}, {Value: "pt", Label: "Portugal"}, {Value: "nl", Label: "Netherlands", Disabled: true}, }, }) }

Multiple With Label

Use the Label prop for a simple text label above the field.

12345678910111213141516171819202122
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SelectMultipleWithLabelExample() { @popui.Select(props.Select{ Multiple: true, ID: "countries-with-label", Name: "countries", Label: "Countries", Placeholder: "Choose countries", Options: []props.SelectOption{ {Value: "es", Label: "Spain"}, {Value: "fr", Label: "France"}, {Value: "de", Label: "Germany"}, {Value: "it", Label: "Italy"}, }, }) }

Multiple With Description

Give an option a Description to render dimmed text next to its label in the dropdown.

123456789101112131415161718192021
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SelectMultipleWithDescriptionExample() { @popui.Select(props.Select{ Multiple: true, Name: "currencies", Placeholder: "Choose currencies", Options: []props.SelectOption{ {Value: "eur", Label: "EUR", Description: "Euro", Selected: true}, {Value: "usd", Label: "USD", Description: "US Dollar"}, {Value: "gbp", Label: "GBP", Description: "British Pound"}, {Value: "jpy", Label: "JPY", Description: "Japanese Yen"}, {Value: "chf", Label: "CHF", Description: "Swiss Franc"}, }, }) }

Multiple Searchable

Set Searchable to add a filter box inside the dropdown. Useful when there are many options.

123456789101112131415161718192021222324252627
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SelectMultipleSearchableExample() { @popui.Select(props.Select{ Multiple: true, ID: "countries-searchable", Name: "countries", Label: "Countries", Placeholder: "Choose countries", Searchable: true, Options: []props.SelectOption{ {Value: "es", Label: "Spain", Selected: true}, {Value: "fr", Label: "France"}, {Value: "de", Label: "Germany"}, {Value: "it", Label: "Italy"}, {Value: "pt", Label: "Portugal"}, {Value: "nl", Label: "Netherlands"}, {Value: "be", Label: "Belgium"}, {Value: "at", Label: "Austria"}, }, }) }

Multiple Disabled

The field can be disabled to prevent user interaction. Selected values are still displayed but cannot be changed.

12345678910111213141516171819
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SelectMultipleDisabledExample() { @popui.Select(props.Select{ Multiple: true, Name: "countries", Disabled: true, Options: []props.SelectOption{ {Value: "es", Label: "Spain", Selected: true}, {Value: "fr", Label: "France", Selected: true}, {Value: "de", Label: "Germany"}, }, }) }

Multiple With Error

The field can display error messages for validation feedback.

Please select at least one country

1234567891011121314151617181920212223242526
package examples import ( "errors" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SelectMultipleWithErrorExample() { @popui.Select(props.Select{ Multiple: true, ID: "countries-with-error", Name: "countries", Label: "Countries", Placeholder: "Choose countries", Error: props.Error{ Error: errors.New("Please select at least one country"), }, Options: []props.SelectOption{ {Value: "es", Label: "Spain"}, {Value: "fr", Label: "France"}, {Value: "de", Label: "Germany"}, {Value: "it", Label: "Italy"}, }, }) }

API Reference

Select

Dropdown selection control. Renders a native single-choice select by default, or a tag-chip combobox with Multiple.

NameTypeDefaultDescription
ID string-Unique identifier. The Multiple variant auto-generates one when omitted so the label links correctly
Class string-Additional CSS classes to merge with the field styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.), applied to the select or the combobox control
Name string-Name attribute for form submission. With Multiple, each selected value is submitted under this name
Label string-Simple label text displayed above the field
Disabled boolfalseDisables the field
Autofocus boolfalseAutomatically focuses the select on page load (single variant only)
Multiple boolfalseSwitches to the multi-selection tag-chip combobox variant
Required boolfalseMarks the field as required for form validation
Placeholder string"Select options"Text shown inside the field when nothing is selected (Multiple variant only)
Searchable boolfalseAdds a search box inside the dropdown to filter options (Multiple variant only)
Error props.Error-Error configuration to display validation feedback below the field
Options []SelectOption-Array of options to render. When provided, child option elements are ignored

SelectOption

Configuration for individual select options when using the Options property.

NameTypeDefaultDescription
Value string-The value attribute of the option element
Label string-The text displayed for the option
Description string-Dimmed text rendered next to the label in the dropdown (Multiple variant only)
Selected boolfalseWhether the option is initially selected
Disabled boolfalseWhether the option is disabled

Error

Error configuration for displaying validation feedback.

NameTypeDefaultDescription
Error error-Go error object to display (calls .Error() method)
Text string-Text string to display as error message
Class string-Additional CSS classes to merge with error styles
Attributes templ.Attributes-Additional HTML attributes for the error element

Separator

Horizontal divider with a dashed line for visual separation.

Content above


Content below

12345678910111213
package examples import "github.com/invopop/popui.go" templ SeparatorExample() { @popui.P() { Content above } @popui.Separator() @popui.P() { Content below } }

Custom Spacing

Adjust vertical spacing with custom classes.

Content above


Content below

123456789101112131415161718
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SeparatorCustomSpacingExample() { @popui.P() { Content above } @popui.Separator(props.Separator{ Class: "my-8", }) @popui.P() { Content below } }

With Content

Children are rendered centered on top of the dashed line with a solid background that hides the border behind them.

Content above


or

Content below

123456789101112131415
package examples import "github.com/invopop/popui.go" templ SeparatorWithContentExample() { @popui.P() { Content above } @popui.Separator() { or } @popui.P() { Content below } }

API Reference

Separator

Horizontal separator component with dashed line styling.

NameTypeDefaultDescription
ID string-Unique identifier for the separator element
Class string-Additional CSS classes to merge with separator styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)

SidePanel

Floating side panel that overlays one edge of the viewport.

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SidePanelExample() { @popui.Button(props.Button{ Attributes: templ.Attributes{ "@click": "window.dispatchEvent(new CustomEvent('popui-sidepanel-open', {detail: 'side-panel-example'}))", }, }) { Open side panel } @popui.SidePanel(props.SidePanel{ID: "side-panel-example", Width: 480}) { @popui.SidePanelHeader(props.SidePanelHeader{ SidePanelID: "side-panel-example", Title: "SIREN 552100554", }) @popui.Label(props.Label{Class: "px-4 py-3 text-base text-foreground"}) { Details } @popui.DescriptionList(props.DescriptionList{Class: "w-auto space-y-1 mx-4 pb-4 border-b border-border"}) { @popui.DescriptionListItem(props.DescriptionListItem{Inline: true, Label: "Given name", Value: "Camille"}) @popui.DescriptionListItem(props.DescriptionListItem{Inline: true, Label: "Surname", Value: "Durand"}) @popui.DescriptionListItem(props.DescriptionListItem{Inline: true, Label: "Role", Value: "Director"}) @popui.DescriptionListItem(props.DescriptionListItem{Inline: true, Label: "Reporting", Value: "Enabled"}) @popui.DescriptionListItem(props.DescriptionListItem{Inline: true, Label: "VAT regime", Value: "Réel normal mensuel"}) @popui.DescriptionListItem(props.DescriptionListItem{Inline: true, Label: "Decided", Value: "2026-03-14"}) @popui.DescriptionListItem(props.DescriptionListItem{ Inline: true, Label: "Silo Entry ID", Value: "ee42413c-79fc-42d0-a7f7-65f76990ab20", PrefixLength: 23, Actions: []props.DescriptionListAction{ {Icon: icons.Duplicate(), Copy: "ee42413c-79fc-42d0-a7f7-65f76990ab20", Attributes: templ.Attributes{"aria-label": "Copy"}}, {Icon: icons.ExternalLink(), URL: templ.SafeURL("https://app.invopop.com/silo-entry/ee42413c-79fc-42d0-a7f7-65f76990ab20"), Attributes: templ.Attributes{"aria-label": "Open in a new tab"}}, }, }) } @popui.Tabs(props.Tabs{ Variant: "pill", Class: "px-4 pt-4 text-base", Tabs: []props.TabItem{ {Value: "directory", Label: "Directory"}, {Value: "reporting", Label: "Reporting"}, }, }) { @popui.Tab(props.Tab{Value: "directory"}) { @popui.DescriptionList(props.DescriptionList{Class: "w-full space-y-2"}) { @popui.DescriptionListItem(props.DescriptionListItem{Label: "Name", Value: "Durand SARL", Actions: []props.DescriptionListAction{ {Icon: icons.Duplicate(), Copy: "Durand SARL", Attributes: templ.Attributes{"aria-label": "Copy"}}, }}) @popui.DescriptionListItem(props.DescriptionListItem{Label: "Endpoint", Value: "0009:552100554", Actions: []props.DescriptionListAction{ {Icon: icons.Duplicate(), Copy: "0009:552100554", Attributes: templ.Attributes{"aria-label": "Copy"}}, }}) } } @popui.Tab(props.Tab{Value: "reporting"}) { @popui.DescriptionList(props.DescriptionList{Class: "w-full space-y-2"}) { @popui.DescriptionListItem(props.DescriptionListItem{Label: "SIREN", Value: "552100554", Actions: []props.DescriptionListAction{ {Icon: icons.Duplicate(), Copy: "552100554", Attributes: templ.Attributes{"aria-label": "Copy"}}, }}) @popui.DescriptionListItem(props.DescriptionListItem{Label: "Cadence", Value: "Monthly", Actions: []props.DescriptionListAction{ {Icon: icons.Duplicate(), Copy: "Monthly", Attributes: templ.Attributes{"aria-label": "Copy"}}, }}) @popui.DescriptionListItem(props.DescriptionListItem{Label: "Next period", Value: "2026-07-31", Actions: []props.DescriptionListAction{ {Icon: icons.Duplicate(), Copy: "2026-07-31", Attributes: templ.Attributes{"aria-label": "Copy"}}, }}) @popui.DescriptionListItem(props.DescriptionListItem{Label: "Last period", Value: "2026-06-30", Actions: []props.DescriptionListAction{ {Icon: icons.ExternalLink(), URL: templ.SafeURL("https://app.invopop.com/"), Attributes: templ.Attributes{"aria-label": "Open in a new tab"}}, }}) } } } } }

API Reference

SidePanel

Fixed-position side panel that overlays one edge of the viewport. Open / close is driven by popui-sidepanel-open / popui-sidepanel-close window events whose event.detail must match the panel's ID.

NameTypeDefaultDescription
ID string-Unique identifier for the panel's <aside> element and the event scope for open/close.
Class string-Additional CSS classes merged with the panel's base styling.
Attributes templ.Attributes-Additional HTML attributes applied to the <aside> element.
Position stringrightEdge of the viewport to anchor to. One of props.SidePanelPositionRight or props.SidePanelPositionLeft.
Width int400Panel width in pixels. 0 falls back to 400.

SidePanelHeader

Sticky header bar at the top of a SidePanel. The default close button dispatches popui-sidepanel-close with the matching SidePanelID.

NameTypeDefaultDescription
ID string-Unique identifier for the header element.
Class string-Additional CSS classes merged with the header's base styling.
Attributes templ.Attributes-Additional HTML attributes applied to the header element.
SidePanelID string-ID of the parent SidePanel — used by the default close button to dispatch popui-sidepanel-close with the matching event.detail.
Title string-h1 heading rendered in the centre cell. Truncates on overflow.
CloseAttributes templ.Attributes-Replace the close button's default attributes. The override is responsible for dispatching popui-sidepanel-close to keep the panel's Alpine state in sync.

SignaturePad

A signature capture dialog with typed-name preview and freehand drawing tabs.

A signature capture dialog with a typed-name preview tab and a freehand drawing tab. Place a trigger button with onclick="popuiSignPad.open()". On confirm, POSTs to Action with the signature field (empty = typed name, data-URI = drawn image).

Sign
Jane Smith
123456789101112131415161718192021222324
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SignaturePadExample() { @popui.SignaturePad(props.SignaturePad{ Signer: "Jane Smith", Action: "/sign", Title: "Sign", TabTyped: "Click to sign", TabDraw: "Draw your signature", UseLabel: "Use signature", ClearLabel: "Clear", }) @popui.Button(props.Button{Type: "button", Variant: props.ButtonVariantPrimary, Attributes: templ.Attributes{"onclick": "popuiSignPad.open()"}}) { Sign document } <script> document.getElementById("popui-sign-form").addEventListener("submit", function(e) { e.preventDefault(); }); </script> }

API Reference

SignaturePad

Renders a hidden POST form and a modal dialog for capturing a signature. The Caveat font is served from /_popui/assets/caveat.woff2 via the standard popui asset mount.

NameTypeDefaultDescription
Action *string-Form POST action URL
Signer *string-Full name shown in the typed-signature preview
Title string-Dialog heading
TabTyped string-Label for the typed-name tab
TabDraw string-Label for the freehand drawing tab
UseLabel string-Label for the confirm button
ClearLabel string-Label for the clear button

Slider

A range slider input for selecting numeric values.

123456789101112131415
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SliderExample() { @popui.Slider(props.Slider{ Name: "volume", Min: "0", Max: "100", Value: "50", }) }

With Label

Add a label using the children slot.

1234567891011121314151617181920
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SliderWithLabelExample() { @popui.Slider(props.Slider{ ID: "slider-volume-custom", Name: "volume", Min: "0", Max: "100", Value: "50", }) { @popui.Label(props.Label{ID: "volume"}) { Volume } } }

With Options

Display labeled tick marks using ListOptions.

123456789101112131415161718192021222324252627
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SliderWithOptionsExample() { @popui.Slider(props.Slider{ ID: "slider-size-options", Name: "size", Min: "0", Max: "4", Value: "2", ListOptions: []props.SliderListOption{ {Value: "0", Label: "XS"}, {Value: "1", Label: "S"}, {Value: "2", Label: "M"}, {Value: "3", Label: "L"}, {Value: "4", Label: "XL"}, }, }) { @popui.Label(props.Label{ID: "size"}) { Size } } }

Custom Step

Control the granularity of value changes with the Step prop.

123456789101112131415161718192021
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ SliderCustomStepExample() { @popui.Slider(props.Slider{ ID: "slider-price-custom", Name: "price", Min: "0", Max: "1000", Step: "50", Value: "500", }) { @popui.Label(props.Label{ID: "price"}) { Price Range } } }

API Reference

Slider

A range slider input for selecting numeric values.

NameTypeDefaultDescription
ID string-Unique identifier (auto-generated if not provided)
Class string-Additional CSS classes to merge with slider styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Name string-Form field name
Value string-Initial value of the slider
Min string-Minimum value
Max string-Maximum value
Step string-Step increment for value changes
ListOptions []SliderListOptionnilList of labeled tick marks to display below the slider

SliderListOption

Defines a labeled tick mark for the slider.

NameTypeDefaultDescription
Value string-The value at this position
Label string-The label to display for this value

StatusBadge

Icon-led outcome pill with an optional label: success, failed, warning or running.

Agreement
Company
Identity
Processing
123456789101112131415
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ StatusBadgeExample() { <div class="flex flex-wrap items-center gap-2"> @popui.StatusBadge(props.StatusBadge{Label: "Agreement", Status: "success"}) @popui.StatusBadge(props.StatusBadge{Label: "Company", Status: "failed"}) @popui.StatusBadge(props.StatusBadge{Label: "Identity", Status: "warning"}) @popui.StatusBadge(props.StatusBadge{Label: "Processing", Status: "running"}) </div> }

API Reference

StatusBadge

Status tag component with a leading status icon and an optional label.

NameTypeDefaultDescription
ID string-Unique identifier for the tag element
Class string-Additional CSS classes to merge with base styles
Attributes templ.Attributes-Additional HTML attributes to apply to the tag element
Label string-Optional text label displayed next to the icon
Status stringsuccessIcon variant: success, failed, warning, running

Table

Display data in a structured table format with automatic styling for headers, cells, and borders.

NameEmailRole
John Doejohn@example.comAdmin
Jane Smithjane@example.comUser
Bob Johnsonbob@example.comEditor
1234567891011121314151617181920212223242526272829303132
package examples import "github.com/invopop/popui.go" templ TableExample() { @popui.Table() { <thead> <tr> <th>Name</th> <th>Email</th> <th>Role</th> </tr> </thead> <tbody> <tr> <td>John Doe</td> <td>john@example.com</td> <td>Admin</td> </tr> <tr> <td>Jane Smith</td> <td>jane@example.com</td> <td>User</td> </tr> <tr> <td>Bob Johnson</td> <td>bob@example.com</td> <td>Editor</td> </tr> </tbody> } }

Variants

Tables support a card variant that adds an outer border. Default tables have no outer border.

Default (no border)

NameEmailRole
John Doejohn@example.comAdmin
Jane Smithjane@example.comUser

Card variant (with border)

NameEmailRole
John Doejohn@example.comAdmin
Jane Smithjane@example.comUser
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TableVariantsExample() { <div class="flex flex-col gap-6"> <div> <h3 class="text-sm font-medium mb-2">Default (no border)</h3> @popui.Table() { <thead> <tr> <th>Name</th> <th>Email</th> <th>Role</th> </tr> </thead> <tbody> <tr> <td>John Doe</td> <td>john@example.com</td> <td>Admin</td> </tr> <tr> <td>Jane Smith</td> <td>jane@example.com</td> <td>User</td> </tr> </tbody> } </div> <div> <h3 class="text-sm font-medium mb-2">Card variant (with border)</h3> @popui.Table(props.Table{Variant: "card"}) { <thead> <tr> <th>Name</th> <th>Email</th> <th>Role</th> </tr> </thead> <tbody> <tr> <td>John Doe</td> <td>john@example.com</td> <td>Admin</td> </tr> <tr> <td>Jane Smith</td> <td>jane@example.com</td> <td>User</td> </tr> </tbody> } </div> </div> }

Clickable Rows

Add hover effects to table rows by passing additional classes via the Class prop.

ProductStatusPrice
Widget AAvailable$29.99
Widget BOut of Stock$39.99
Widget CAvailable$49.99
12345678910111213141516171819202122232425262728293031323334353637
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TableClickableExample() { @popui.Table(props.Table{ Class: "[&_tr:hover_td]:bg-background-default-secondary [&_tr:hover_td]:cursor-pointer", }) { <thead> <tr> <th>Product</th> <th>Status</th> <th>Price</th> </tr> </thead> <tbody> <tr> <td>Widget A</td> <td>Available</td> <td>$29.99</td> </tr> <tr> <td>Widget B</td> <td>Out of Stock</td> <td>$39.99</td> </tr> <tr> <td>Widget C</td> <td>Available</td> <td>$49.99</td> </tr> </tbody> } }

Right-Aligned Cells

Right-align specific columns using the Class prop with arbitrary variants like [&_th:last-child]:text-right.

ItemQuantityAmount
Product A3$89.97
Product B1$39.99
Product C2$99.98
12345678910111213141516171819202122232425262728293031323334353637
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TableRightAlignExample() { @popui.Table(props.Table{ Class: "[&_th:last-child]:text-right [&_td:last-child]:text-right", }) { <thead> <tr> <th>Item</th> <th>Quantity</th> <th>Amount</th> </tr> </thead> <tbody> <tr> <td>Product A</td> <td>3</td> <td>$89.97</td> </tr> <tr> <td>Product B</td> <td>1</td> <td>$39.99</td> </tr> <tr> <td>Product C</td> <td>2</td> <td>$99.98</td> </tr> </tbody> } }

With Avatars

Tables can contain any components including avatars. Use the Avatar component for user initials or images.

UserEmailRole
J
John Doe
john@example.comAdmin
S
Jane Smith
jane@example.comEditor
12345678910111213141516171819202122232425262728293031323334353637383940
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TableCustomContentExample() { @popui.Table() { <thead> <tr> <th>User</th> <th>Email</th> <th>Role</th> </tr> </thead> <tbody> <tr> <td> <div class="flex items-center gap-2"> @popui.Avatar(props.Avatar{Initial: "J"}) <span>John Doe</span> </div> </td> <td>john@example.com</td> <td>Admin</td> </tr> <tr> <td> <div class="flex items-center gap-2"> @popui.Avatar(props.Avatar{Initial: "S"}) <span>Jane Smith</span> </div> </td> <td>jane@example.com</td> <td>Editor</td> </tr> </tbody> } }

Table Pagination

Add pagination controls to your table with TablePagination component. Uses AnchorButton with URLs for navigation and supports custom action buttons via children slot.

Invoice IDCustomerAmountStatus
INV-001Acme Corp$1,234.56Paid
INV-002Tech Solutions$987.65Pending
INV-003Global Inc$2,345.67Paid
/ 260
25,991 invoices
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TablePaginationExample() { <div class="border border-border rounded-lg overflow-hidden"> @popui.Table() { <thead> <tr> <th>Invoice ID</th> <th>Customer</th> <th>Amount</th> <th>Status</th> </tr> </thead> <tbody> <tr> <td>INV-001</td> <td>Acme Corp</td> <td>$1,234.56</td> <td>Paid</td> </tr> <tr> <td>INV-002</td> <td>Tech Solutions</td> <td>$987.65</td> <td>Pending</td> </tr> <tr> <td>INV-003</td> <td>Global Inc</td> <td>$2,345.67</td> <td>Paid</td> </tr> </tbody> } @popui.TablePagination(props.TablePagination{ CurrentPage: 1, TotalPages: 260, TotalItems: 25991, RowsPerPage: 100, RowsPerPageOptions: []int{10, 25, 50, 100, 250}, ShowRowsPerPage: true, ItemsLabel: "invoices", FirstPageURL: "?page=1", PrevPageURL: "?page=0", NextPageURL: "?page=2", LastPageURL: "?page=260", }) { @popui.ButtonGroup() { @popui.Button(props.Button{ Type: "button", Size: "sm", Variant: "secondary", }) { Export } @popui.Button(props.Button{ Type: "button", Size: "sm", Variant: "primary", }) { Create Invoice } } } </div> }

Pagination with Alpine.js

Use the Elements prop to add Alpine.js directives for client-side pagination. Bind data-disabled to control the disabled state. The component automatically applies disabled styles via data attributes without needing to know internal CSS classes.

Invoice IDCustomerAmountStatus
INV-001Acme Corp$1,234.56Paid
INV-002Tech Solutions$987.65Pending
INV-003Global Inc$2,345.67Paid
/ 260
25,991 invoices
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TablePaginationAlpineExample() { <div x-data="{ currentPage: 1, totalPages: 260, totalItems: 25991, rowsPerPage: 100, itemsLabel: 'invoices', goToPage(page) { const pageNum = parseInt(page); if (pageNum >= 1 && pageNum <= this.totalPages) { this.currentPage = pageNum; // Here you would typically fetch new data from your API console.log('Navigating to page:', pageNum); } }, changeRowsPerPage(value) { this.rowsPerPage = parseInt(value); this.currentPage = 1; // Recalculate total pages based on new rows per page console.log('Changed rows per page to:', value); } }" class="border border-border rounded-lg overflow-hidden" > @popui.Table() { <thead> <tr> <th>Invoice ID</th> <th>Customer</th> <th>Amount</th> <th>Status</th> </tr> </thead> <tbody> <tr> <td>INV-001</td> <td>Acme Corp</td> <td>$1,234.56</td> <td>Paid</td> </tr> <tr> <td>INV-002</td> <td>Tech Solutions</td> <td>$987.65</td> <td>Pending</td> </tr> <tr> <td>INV-003</td> <td>Global Inc</td> <td>$2,345.67</td> <td>Paid</td> </tr> </tbody> } @popui.TablePagination(props.TablePagination{ CurrentPage: 1, TotalPages: 260, TotalItems: 25991, RowsPerPage: 100, RowsPerPageOptions: []int{10, 25, 50, 100, 250}, ShowRowsPerPage: true, ItemsLabel: "invoices", FirstPageURL: "#", PrevPageURL: "#", NextPageURL: "#", LastPageURL: "#", Elements: props.TablePaginationElements{ First: templ.Attributes{ "@click.prevent": "goToPage(1)", "x-bind:data-disabled": "currentPage === 1", }, Prev: templ.Attributes{ "@click.prevent": "goToPage(currentPage - 1)", "x-bind:data-disabled": "currentPage === 1", }, Next: templ.Attributes{ "@click.prevent": "goToPage(currentPage + 1)", "x-bind:data-disabled": "currentPage === totalPages", }, Last: templ.Attributes{ "@click.prevent": "goToPage(totalPages)", "x-bind:data-disabled": "currentPage === totalPages", }, Page: templ.Attributes{ "x-model.number": "currentPage", "@input": "goToPage($event.target.value)", }, Select: templ.Attributes{ "x-model": "rowsPerPage", "@change": "changeRowsPerPage($event.target.value)", }, TotalPages: templ.Attributes{ "x-text": "totalPages", }, TotalItems: templ.Attributes{ "x-text": "`${totalItems} ${itemsLabel}`", }, }, }) </div> }

Horizontal Scroll

Enable horizontal scrolling for wide tables. Useful for tables with many columns that exceed the viewport width.

Product IDProduct NameCategoryPriceStockSupplierLocationLast Updated
PRD-001Wireless MouseElectronics$29.99156TechCorp IncWarehouse A2024-01-15
PRD-002Mechanical KeyboardElectronics$89.9987KeyMasters LtdWarehouse B2024-01-14
PRD-003USB-C HubAccessories$45.50203ConnectProWarehouse A2024-01-16
PRD-004Laptop StandAccessories$34.99142ErgoSupply CoWarehouse C2024-01-13
PRD-005Webcam HD 1080pElectronics$67.9998VisionTechWarehouse B2024-01-17
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TableScrollHorizontalExample() { @popui.Table(props.Table{ ScrollHorizontal: true, Variant: "card", }) { <colgroup> <col style="width: 150px;"/> <col style="width: 200px;"/> <col style="width: 150px;"/> <col style="width: 120px;"/> <col style="width: 100px;"/> <col style="width: 200px;"/> <col style="width: 150px;"/> <col style="width: 180px;"/> </colgroup> <thead> <tr> <th>Product ID</th> <th>Product Name</th> <th>Category</th> <th>Price</th> <th>Stock</th> <th>Supplier</th> <th>Location</th> <th>Last Updated</th> </tr> </thead> <tbody> <tr> <td>PRD-001</td> <td>Wireless Mouse</td> <td>Electronics</td> <td>$29.99</td> <td>156</td> <td>TechCorp Inc</td> <td>Warehouse A</td> <td>2024-01-15</td> </tr> <tr> <td>PRD-002</td> <td>Mechanical Keyboard</td> <td>Electronics</td> <td>$89.99</td> <td>87</td> <td>KeyMasters Ltd</td> <td>Warehouse B</td> <td>2024-01-14</td> </tr> <tr> <td>PRD-003</td> <td>USB-C Hub</td> <td>Accessories</td> <td>$45.50</td> <td>203</td> <td>ConnectPro</td> <td>Warehouse A</td> <td>2024-01-16</td> </tr> <tr> <td>PRD-004</td> <td>Laptop Stand</td> <td>Accessories</td> <td>$34.99</td> <td>142</td> <td>ErgoSupply Co</td> <td>Warehouse C</td> <td>2024-01-13</td> </tr> <tr> <td>PRD-005</td> <td>Webcam HD 1080p</td> <td>Electronics</td> <td>$67.99</td> <td>98</td> <td>VisionTech</td> <td>Warehouse B</td> <td>2024-01-17</td> </tr> </tbody> } }

Sticky Header & Frozen First Column

Pin the header (StickyHeader), scroll wide tables horizontally (ScrollHorizontal), and freeze the first column (StickyColumn); RootClass must be a bounded vertical scroll container. Scroll both directions.

IDNameEmailRoleTeamLocationStatus
usr001John Doejohn@example.comAdminPlatformBerlinActive
usr002Jane Smithjane@example.comUserBillingMadridActive
usr003Bob Johnsonbob@example.comEditorContent-Invited
usr004Alice Brownalice@example.comAdminPlatformLisbonActive
usr005Charlie Davischarlie@example.comUserSupportParisSuspended
usr006Dana Evansdana@example.comEditorContentRomeActive
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TableStickyExample() { @popui.Table(props.Table{ RootClass: "max-h-64 overflow-auto", ScrollHorizontal: true, StickyColumn: true, StickyHeader: true, Resizable: true, }) { <thead> <tr> <th>ID</th> <th>Name</th> <th>Email</th> <th>Role</th> <th>Team</th> <th>Location</th> <th>Status</th> </tr> </thead> <tbody> <tr> <td>usr001</td> <td>John Doe</td> <td>john@example.com</td> <td>Admin</td> <td>Platform</td> <td>Berlin</td> <td>Active</td> </tr> <tr> <td>usr002</td> <td>Jane Smith</td> <td>jane@example.com</td> <td>User</td> <td>Billing</td> <td>Madrid</td> <td>Active</td> </tr> <tr> <td>usr003</td> <td>Bob Johnson</td> <td>bob@example.com</td> <td>Editor</td> <td>Content</td> <td>-</td> <td>Invited</td> </tr> <tr> <td>usr004</td> <td>Alice Brown</td> <td>alice@example.com</td> <td>Admin</td> <td>Platform</td> <td>Lisbon</td> <td>Active</td> </tr> <tr> <td>usr005</td> <td>Charlie Davis</td> <td>charlie@example.com</td> <td>User</td> <td>Support</td> <td>Paris</td> <td>Suspended</td> </tr> <tr> <td>usr006</td> <td>Dana Evans</td> <td>dana@example.com</td> <td>Editor</td> <td>Content</td> <td>Rome</td> <td>Active</td> </tr> </tbody> } }

API Reference

Table

A table component with automatic styling for borders, spacing, and typography. Full-width layout, row-hover tint, and column-title dividers are always applied — no configuration needed. Compose cells with plain <td> / <th>.

NameTypeDefaultDescription
ID string-Unique identifier for the table element
Class string-Additional CSS classes to merge with base styles. Use Tailwind's arbitrary variants like [&_tr:hover_td]:bg-gray-100 for advanced styling
Attributes templ.Attributes-Additional HTML attributes to apply to the table element
Variant string-Visual style: 'card' adds outer border and rounded corners
RootClass string-Classes for the scroll wrapper around the table. Use to bound height + enable vertical scroll for StickyHeader (e.g. 'flex-1 min-h-0 overflow-y-auto')
ScrollHorizontal boolfalseWide, horizontally-scrolling table: the body scrolls sideways. Pair with StickyColumn to keep the first column pinned during the scroll
StickyColumn boolfalsePin the first column to the left with a full-height divider so the identity column never detaches during a horizontal scroll. Only visible alongside ScrollHorizontal
StickyHeader boolfalsePin the <thead> row to the top while the body scrolls. Requires RootClass to make the wrapper a bounded vertical scroll container
Resizable boolfalseLet the user drag the right edge of each header cell to resize the column. Drag handles + behavior are provided by popui (CSS + popui.js); no consumer script needed

TablePagination

Pagination controls for tables with page navigation, rows per page selector, and total count display. Uses AnchorButton for URL-based navigation. Supports a children slot for custom action buttons.

NameTypeDefaultDescription
ID string-Unique identifier for the pagination container
Class string-Additional CSS classes to merge with base styles
Attributes templ.Attributes-Additional HTML attributes for the container
CurrentPage int1Current active page number (1-indexed)
TotalPages int1Total number of pages available
TotalItems int0Total count of items across all pages
RowsPerPage int100Number of rows displayed per page
RowsPerPageOptions []int[10, 25, 50, 100]Available options for rows per page dropdown
ShowRowsPerPage boolfalseWhether to show the rows per page dropdown
ItemsLabel stringitemsLabel for the total count (e.g., 'invoices', 'users')
FirstPageURL templ.SafeURL-URL for the first page navigation button
PrevPageURL templ.SafeURL-URL for the previous page navigation button
NextPageURL templ.SafeURL-URL for the next page navigation button
LastPageURL templ.SafeURL-URL for the last page navigation button
Elements TablePaginationElements-Custom attributes for interactive elements. Use this to add Alpine.js or other JS framework directives. When provided, disables server-side conditional classes to allow JS framework control

TablePaginationElements

Defines custom attributes for each interactive element in table pagination. Allows integration with Alpine.js or other JavaScript frameworks while maintaining component styling. Buttons automatically style based on data-disabled attribute.

NameTypeDefaultDescription
First templ.Attributes-Attributes for the first page button. Use x-bind:data-disabled for dynamic state
Prev templ.Attributes-Attributes for the previous page button. Use x-bind:data-disabled for dynamic state
Next templ.Attributes-Attributes for the next page button. Use x-bind:data-disabled for dynamic state
Last templ.Attributes-Attributes for the last page button. Use x-bind:data-disabled for dynamic state
Page templ.Attributes-Attributes for the page number input field (e.g., x-model for two-way binding)
Select templ.Attributes-Attributes for the rows per page select dropdown
TotalPages templ.Attributes-Attributes for the total pages text span (e.g., x-text for dynamic updates)
TotalItems templ.Attributes-Attributes for the total items count span

Tabs

Interactive tab navigation component with default and pill variants.

1234567891011121314
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TabsExample() { @popui.Tabs(props.Tabs{Tabs: []props.TabItem{ {Value: "account", Label: "Account"}, {Value: "settings", Label: "Settings"}, {Value: "privacy", Label: "Privacy"}, }}) }

Active State

Seed the initially-active tab with the Tabs Active prop (matches a tab's Value).

1234567891011121314
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TabsActiveExample() { @popui.Tabs(props.Tabs{Active: "details", Tabs: []props.TabItem{ {Value: "overview", Label: "Overview"}, {Value: "details", Label: "Details"}, {Value: "history", Label: "History"}, }}) }

Variants

Tabs come in two variants: default (underline) and pill.

123456789101112131415161718192021
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TabsVariantsExample() { <div class="space-y-6"> @popui.Tabs(props.Tabs{Tabs: []props.TabItem{ {Value: "overview", Label: "Overview"}, {Value: "details", Label: "Details"}, {Value: "history", Label: "History"}, }}) @popui.Tabs(props.Tabs{Variant: "pill", Tabs: []props.TabItem{ {Value: "profile", Label: "Profile"}, {Value: "preferences", Label: "Preferences"}, {Value: "security", Label: "Security"}, }}) </div> }

With Icons

Tabs can contain icons alongside text.

123456789101112131415
package examples import ( "github.com/invopop/icons" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TabsWithIconsExample() { @popui.Tabs(props.Tabs{Tabs: []props.TabItem{ {Value: "account", Label: "Account", Icon: icons.User()}, {Value: "settings", Label: "Settings", Icon: icons.Settings()}, {Value: "privacy", Label: "Privacy", Icon: icons.Lock()}, }}) }

API Reference

Tabs

Self-contained tabbed view: renders the trigger row from Tabs, owns the Alpine scope + switching logic, and hosts one Tab content panel per tab in its children. Omit the children for a stand-alone trigger row.

NameTypeDefaultDescription
ID string-Unique identifier for the tabs element
Class string-Additional CSS classes to merge with base styles
Attributes templ.Attributes-Additional HTML attributes to apply to the tabs container
Variant stringdefaultStyle variant: "default" for underline tabs or "pill" for pill-style tabs
Model stringtabThe Alpine variable holding the active tab Value. Match it on the child Tabs (their default is also "tab").
Active stringfirst tabTab Value selected on first render. Defaults to the first tab's Value.
Tabs []props.TabItem-The ordered trigger row.

TabItem

One entry in the Tabs trigger row.

NameTypeDefaultDescription
Value string-Identifies the tab; assigned to the Alpine Model on click and matched by the content Tab.
Label string-Visible trigger text.
Icon templ.Component-Optional leading icon rendered before the label.

Tab

One tab's content panel, placed inside Tabs. Shown only while the active tab equals Value.

NameTypeDefaultDescription
ID string-Unique identifier for the panel element
Class string-Additional CSS classes to merge with base styles
Attributes templ.Attributes-Additional HTML attributes to apply to the panel
Value string-The tab this panel belongs to (matches a TabItem.Value).
Model stringtabThe Alpine variable to test. Set only when the parent Tabs uses a custom Model.

TagStatus

Status indicators with optional dots and different color variants.

DraftPaidErrorProcessing
123456789101112131415
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TagStatusExample() { <div class="flex items-center gap-2"> @popui.TagStatus(props.TagStatus{Label: "Draft", Status: "orange"}) @popui.TagStatus(props.TagStatus{Label: "Paid", Status: "green"}) @popui.TagStatus(props.TagStatus{Label: "Error", Status: "red"}) @popui.TagStatus(props.TagStatus{Label: "Processing", Status: "yellow"}) </div> }

With Dot

Add a dot indicator using the Dot prop.

Draft Paid Error
123456789101112131415
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TagStatusWithDotExample() { <div class="flex items-center gap-2"> @popui.TagStatus(props.TagStatus{Label: "Draft", Status: "orange", Dot: true}) @popui.TagStatus(props.TagStatus{Label: "Paid", Status: "green", Dot: true}) @popui.TagStatus(props.TagStatus{Label: "Error", Status: "red", Dot: true}) @popui.TagStatus(props.TagStatus{Dot: true, Status: "blue"}) </div> }

Colors

Available color variants for different statuses.

GreyGreenYellowRedOrangeBluePurpleOliveTealCrimsonSteel BlueEmpty
1234567891011121314151617181920212223
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TagStatusColorsExample() { <div class="flex flex-wrap items-center gap-2"> @popui.TagStatus(props.TagStatus{Label: "Grey", Status: "grey"}) @popui.TagStatus(props.TagStatus{Label: "Green", Status: "green"}) @popui.TagStatus(props.TagStatus{Label: "Yellow", Status: "yellow"}) @popui.TagStatus(props.TagStatus{Label: "Red", Status: "red"}) @popui.TagStatus(props.TagStatus{Label: "Orange", Status: "orange"}) @popui.TagStatus(props.TagStatus{Label: "Blue", Status: "blue"}) @popui.TagStatus(props.TagStatus{Label: "Purple", Status: "purple"}) @popui.TagStatus(props.TagStatus{Label: "Olive", Status: "olive"}) @popui.TagStatus(props.TagStatus{Label: "Teal", Status: "teal"}) @popui.TagStatus(props.TagStatus{Label: "Crimson", Status: "crimson"}) @popui.TagStatus(props.TagStatus{Label: "Steel Blue", Status: "steelBlue"}) @popui.TagStatus(props.TagStatus{Label: "Empty", Status: "empty"}) </div> }

API Reference

TagStatus

Status tag component with color variants and optional dot indicator.

NameTypeDefaultDescription
ID string-Unique identifier for the tag element
Class string-Additional CSS classes to merge with base styles
Attributes templ.Attributes-Additional HTML attributes to apply to the tag element
Label string-Text label displayed in the tag
Status stringgreyColor variant: grey, green, yellow, red, orange, blue, purple, olive, teal, crimson, steelBlue, empty
Dot boolfalseWhether to display a colored dot indicator

Textarea

Multi-line text input field for capturing longer user input with support for labels and validation.

12345678910111213
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TextareaExample() { @popui.Textarea(props.Textarea{ Placeholder: "Enter your message...", Rows: 4, }) }

With Label

Use the Label prop for a simple text label above the textarea.

12345678910111213141516
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TextareaWithLabelExample() { @popui.Textarea(props.Textarea{ ID: "bio", Name: "bio", Label: "Biography", Placeholder: "Tell us about yourself...", Rows: 6, }) }

Custom Label

For advanced label features like hints, render a Label component separately with proper spacing using a flex container.

1234567891011121314151617181920
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TextareaCustomLabelExample() { <div class="flex flex-col gap-2"> @popui.Label(props.Label{ID: "comments", Hint: "Share your thoughts in detail"}) { Comments } @popui.Textarea(props.Textarea{ ID: "comments", Name: "comments", Placeholder: "Enter your comments...", Rows: 5, }) </div> }

Disabled & Read-only

Textarea can be disabled to prevent interaction or set to read-only to prevent editing.

1234567891011121314
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TextareaDisabledExample() { @popui.Textarea(props.Textarea{ Value: "This textarea is disabled and cannot be edited.", Disabled: true, Rows: 3, }) }

With Error

Textarea can display error messages for validation feedback.

Message must be at least 10 characters long

1234567891011121314151617181920
package examples import ( "errors" "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TextareaWithErrorExample() { @popui.Textarea(props.Textarea{ ID: "message", Name: "message", Label: "Message", Placeholder: "Enter your message...", Rows: 4, Error: props.Error{ Error: errors.New("Message must be at least 10 characters long"), }, }) }

Monospaced Font

Use the Class prop with font-mono for code or monospaced text display.

123456789101112131415
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TextareaMonospacedExample() { @popui.Textarea(props.Textarea{ Label: "Code Snippet", Class: "font-mono", Placeholder: "Enter code here...", Rows: 6, }) }

Contenteditable

Use Contenteditable for rich text editing with a div element instead of a textarea. It renders as a contenteditable div that can display formatted content.

This is a contenteditable div. You can use formatted text and it will render properly.
123456789101112131415161718192021
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TextareaContenteditableExample() { <div class="space-y-4"> @popui.Textarea(props.Textarea{ Label: "Standard Textarea", Value: "This is plain text in a textarea element. HTML tags like <strong>bold</strong> are displayed as text.", Rows: 3, }) @popui.Contenteditable(props.Textarea{ Label: "Contenteditable Div", Value: "This is a contenteditable div. You can use <strong>formatted</strong> <em>text</em> and it will render properly.", Rows: 3, }) </div> }

API Reference

Textarea

Multi-line text input field with support for labels and validation.

NameTypeDefaultDescription
ID string-Unique identifier for the textarea element
Class string-Additional CSS classes to merge with textarea styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Name string-Name attribute for form submission
Placeholder string-Placeholder text displayed when textarea is empty
Value string-Initial or current value of the textarea
Label string-Simple label text displayed above the textarea
Rows int4Number of visible text rows
Disabled boolfalseDisables the textarea
Readonly boolfalseMakes the textarea read-only
Required boolfalseMarks the textarea as required for form validation
Autofocus boolfalseAutomatically focuses the textarea on page load
Error props.Error-Error configuration to display validation feedback below the textarea

Error

Error configuration for displaying validation feedback.

NameTypeDefaultDescription
Error error-Go error object to display (calls .Error() method)
Text string-Text string to display as error message
Class string-Additional CSS classes to merge with error styles
Attributes templ.Attributes-Additional HTML attributes for the error element

Toast

Dark floating notification with a type icon, message, optional description, and optional action button.

Toasts are hidden by default and shown with popui.showToast(id), or declaratively from any button with a data-toast-trigger attribute. They appear at the bottom right of the screen and hide after three seconds. Only one toast is visible at a time.

Success toast message

Error toast message

Info toast message

1234567891011121314151617181920212223242526272829303132333435363738394041
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ ToastExample() { <div class="flex flex-wrap gap-2"> @popui.Button(props.Button{ Attributes: templ.Attributes{"data-toast-trigger": "toast-success"}, }) { Show success toast } @popui.Button(props.Button{ Attributes: templ.Attributes{"data-toast-trigger": "toast-error"}, }) { Show error toast } @popui.Button(props.Button{ Attributes: templ.Attributes{"data-toast-trigger": "toast-info"}, }) { Show info toast } </div> @popui.Toast(props.Toast{ ID: "toast-success", Type: props.ToastTypeSuccess, Message: "Success toast message", }) @popui.Toast(props.Toast{ ID: "toast-error", Type: props.ToastTypeError, Message: "Error toast message", }) @popui.Toast(props.Toast{ ID: "toast-info", Type: props.ToastTypeInfo, Message: "Info toast message", }) }

With Description

Add a Description to show secondary detail below the message in a muted color.

Run workflow

Triggered “Send invoice”

Run workflow failed

Triggered “Send invoice”

123456789101112131415161718192021222324252627282930313233
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ ToastDescriptionExample() { <div class="flex flex-wrap gap-2"> @popui.Button(props.Button{ Attributes: templ.Attributes{"data-toast-trigger": "toast-run"}, }) { Run workflow } @popui.Button(props.Button{ Attributes: templ.Attributes{"data-toast-trigger": "toast-run-failed"}, }) { Fail workflow } </div> @popui.Toast(props.Toast{ ID: "toast-run", Type: props.ToastTypeSuccess, Message: "Run workflow", Description: "Triggered “Send invoice”", }) @popui.Toast(props.Toast{ ID: "toast-run-failed", Type: props.ToastTypeError, Message: "Run workflow failed", Description: "Triggered “Send invoice”", }) }

With Action

ActionLabel renders an action button on the right. Set ActionHref to render it as a link, or use ActionAttributes to attach a click handler.

Success toast message

1234567891011121314151617181920212223242526272829303132333435
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ ToastActionExample() { <div class="flex flex-wrap gap-2"> @popui.Button(props.Button{ Attributes: templ.Attributes{"data-toast-trigger": "toast-with-action"}, }) { Show toast with action } @popui.Button(props.Button{ Attributes: templ.Attributes{"data-toast-trigger": "toast-with-link"}, }) { Show toast with link } </div> @popui.Toast(props.Toast{ ID: "toast-with-action", Type: props.ToastTypeSuccess, Message: "Success toast message", ActionLabel: "Action", }) @popui.Toast(props.Toast{ ID: "toast-with-link", Type: props.ToastTypeSuccess, Message: "Run workflow", Description: "Triggered “Send invoice”", ActionLabel: "View run", ActionHref: "#", }) }

Position

Position fixes the toast to any screen corner or edge. Defaults to bottom-right.

Toast at top-left

Toast at top-center

Toast at top-right

Toast at bottom-left

Toast at bottom-center

Toast at bottom-right

1234567891011121314151617181920212223242526272829303132333435
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) var toastPositions = []string{ props.ToastPositionTopLeft, props.ToastPositionTopCenter, props.ToastPositionTopRight, props.ToastPositionBottomLeft, props.ToastPositionBottomCenter, props.ToastPositionBottomRight, } templ ToastPositionExample() { <div class="flex flex-wrap gap-2"> for _, position := range toastPositions { @popui.Button(props.Button{ Attributes: templ.Attributes{"data-toast-trigger": "toast-" + position}, }) { { position } } } </div> for _, position := range toastPositions { @popui.Toast(props.Toast{ ID: "toast-" + position, Type: props.ToastTypeInfo, Message: "Toast at " + position, Position: position, }) } }

Duration

Duration controls how long the toast stays visible, in milliseconds. Defaults to 3000.

This toast lasts one second

This toast lasts ten seconds

123456789101112131415161718192021222324252627282930313233
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ ToastDurationExample() { <div class="flex flex-wrap gap-2"> @popui.Button(props.Button{ Attributes: templ.Attributes{"data-toast-trigger": "toast-short"}, }) { Show for 1 second } @popui.Button(props.Button{ Attributes: templ.Attributes{"data-toast-trigger": "toast-long"}, }) { Show for 10 seconds } </div> @popui.Toast(props.Toast{ ID: "toast-short", Type: props.ToastTypeInfo, Message: "This toast lasts one second", Duration: 1000, }) @popui.Toast(props.Toast{ ID: "toast-long", Type: props.ToastTypeInfo, Message: "This toast lasts ten seconds", Duration: 10000, }) }

API Reference

Toast

Dark floating notification with a type icon, message, optional description, and optional action. Shown via popui.showToast(id) or a data-toast-trigger attribute; only one toast is visible at a time.

NameTypeDefaultDescription
ID string-Unique identifier, used to trigger the toast
Class string-Additional CSS classes to merge with toast styles
Attributes templ.Attributes-Additional HTML attributes (data-*, aria-*, etc.)
Type string-Leading icon type: "success", "error" or "info"
Message string-Main toast text
Description string-Secondary text rendered below the message in a muted color
Position stringbottom-rightScreen position: top-left, top-center, top-right, bottom-left, bottom-center or bottom-right
Duration int3000How long the toast stays visible, in milliseconds
ActionLabel string-Label for the action button on the right side
ActionHref templ.SafeURL-Renders the action as a link instead of a button
ActionAttributes templ.Attributes-Additional HTML attributes for the action element

Typography

Text components for headings, paragraphs, descriptions, and formatted content.

Headings

Title and Subtitle components for page and section headings.

Page Title

Section Subtitle

1234567891011121314
package examples import "github.com/invopop/popui.go" templ TypographyHeadingsExample() { <div class="space-y-4"> @popui.Title() { Page Title } @popui.Subtitle() { Section Subtitle } </div> }

Title Group

TitleGroup pairs a title with a secondary description — stacked by default, or on one baseline with Horizontal. Use it to head sections and grouped form blocks.

Categories Select all that apply
Categories · Select all that apply
1234567891011121314151617181920
package examples import ( "github.com/invopop/popui.go" "github.com/invopop/popui.go/props" ) templ TypographyTitleGroupExample() { <div class="flex flex-col gap-6"> @popui.TitleGroup(props.TitleGroup{ Title: "Categories", Description: "Select all that apply", }) @popui.TitleGroup(props.TitleGroup{ Title: "Categories", Description: "Select all that apply", Horizontal: true, }) </div> }

Paragraphs

Standard paragraph and description text components.

This is a standard paragraph with default styling.

This is a description with secondary text color.

1234567891011121314
package examples import "github.com/invopop/popui.go" templ TypographyParagraphsExample() { <div class="space-y-2"> @popui.P() { This is a standard paragraph with default styling. } @popui.Description() { This is a description with secondary text color. } </div> }

Inline Text

Mark component for highlighted text.

This paragraph contains highlighted text using the Mark component.

12345678910111213
package examples import "github.com/invopop/popui.go" templ TypographyInlineExample() { @popui.P() { <span>This paragraph contains </span> @popui.Mark() { highlighted text } <span>using the Mark component.</span> } }

Alert Messages

Info and Warning components with icons.

This is an informational message with an icon.
This is a warning message with an alert icon.
1234567891011121314
package examples import "github.com/invopop/popui.go" templ TypographyAlertsExample() { <div class="space-y-3"> @popui.Info() { This is an informational message with an icon. } @popui.Warning() { This is a warning message with an alert icon. } </div> }

Prose

Wrapper for raw HTML with Tailwind prose styling.

Prose Heading

This component wraps raw HTML with Tailwind prose styling for consistent typography.

  • Automatically styled lists
  • Formatted headings
  • Consistent spacing
123456789101112131415
package examples import "github.com/invopop/popui.go" templ TypographyProseExample() { @popui.Prose() { <h1>Prose Heading</h1> <p>This component wraps raw HTML with Tailwind prose styling for consistent typography.</p> <ul> <li>Automatically styled lists</li> <li>Formatted headings</li> <li>Consistent spacing</li> </ul> } }

API Reference

Title

H1 heading element with bold styling.

NameTypeDefaultDescription
ID string-Unique identifier
Class string-Additional CSS classes
Attributes templ.Attributes-Additional HTML attributes

TitleGroup

Title with an optional secondary description, stacked or on one baseline.

NameTypeDefaultDescription
ID string-Unique identifier
Class string-Additional CSS classes
Attributes templ.Attributes-Additional HTML attributes
Title string-Bold heading text
Description string-Muted secondary text
Horizontal boolfalsePlaces the description next to the title on the same baseline, separated by a middot

Subtitle

H2 subheading element with medium weight.

NameTypeDefaultDescription
ID string-Unique identifier
Class string-Additional CSS classes
Attributes templ.Attributes-Additional HTML attributes

P

Standard paragraph element.

NameTypeDefaultDescription
ID string-Unique identifier
Class string-Additional CSS classes
Attributes templ.Attributes-Additional HTML attributes

Description

Paragraph with secondary text color.

NameTypeDefaultDescription
ID string-Unique identifier
Class string-Additional CSS classes
Attributes templ.Attributes-Additional HTML attributes

Mark

Inline highlighted text element.

NameTypeDefaultDescription
ID string-Unique identifier
Class string-Additional CSS classes
Attributes templ.Attributes-Additional HTML attributes

Info

Informational message with icon.

NameTypeDefaultDescription
ID string-Unique identifier
Class string-Additional CSS classes
Attributes templ.Attributes-Additional HTML attributes

Warning

Warning message with alert icon.

NameTypeDefaultDescription
ID string-Unique identifier
Class string-Additional CSS classes
Attributes templ.Attributes-Additional HTML attributes

Prose

Container for raw HTML with Tailwind prose styling.

NameTypeDefaultDescription
ID string-Unique identifier
Class string-Additional CSS classes
Attributes templ.Attributes-Additional HTML attributes