Components Cheatsheet
View SourceQuick reference for all 44 Sutra UI components.
Foundation
Button
<.button>Click me</.button>
<.button variant="secondary">Secondary</.button>
<.button variant="destructive">Delete</.button>
<.button variant="outline">Outline</.button>
<.button variant="ghost">Ghost</.button>
<.button variant="link">Link</.button>Button Sizes
<.button size="sm">Small</.button>
<.button size="default">Default</.button>
<.button size="lg">Large</.button>
<.button size="icon" aria-label="Settings">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/></svg>
</.button>Button Navigation
<.button navigate={~p"/users"}>Navigate</.button>
<.button patch={~p"/users/1"}>Patch</.button>
<.button href="https://example.com">Link</.button>Button States
<.button loading>Loading...</.button>
<.button disabled>Disabled</.button>Badge
<.badge>Default</.badge>
<.badge variant="secondary">Secondary</.badge>
<.badge variant="destructive">Error</.badge>
<.badge variant="outline">Outline</.badge>Spinner
<.spinner />
<.spinner size="sm" />
<.spinner size="lg" />Kbd
<.kbd>⌘</.kbd>
<.kbd>Ctrl</.kbd> + <.kbd>C</.kbd>Form Controls
Input
<.input type="text" name="name" />
<.input type="email" name="email" placeholder="you@example.com" />
<.input type="password" name="password" />
<.input type="number" name="quantity" min="0" max="100" />Input Types
| Type | Usage |
|---|---|
text | General text |
email | Email addresses |
password | Passwords |
number | Numeric values |
tel | Phone numbers |
url | URLs |
search | Search fields |
date | Date picker |
time | Time picker |
datetime-local | Date and time |
Textarea
<.textarea name="bio" rows="4" />
<.textarea name="notes" placeholder="Enter notes..." />Label
<.label for="email">Email</.label>Checkbox
<.checkbox id="terms" name="terms" />
<.checkbox id="newsletter" name="newsletter" checked />Switch
<.switch id="notifications" name="notifications" />
<.switch id="dark-mode" name="dark_mode" checked />Radio Group
<.radio_group name="plan">
<:radio value="free">Free</:radio>
<:radio value="pro">Pro</:radio>
<:radio value="enterprise">Enterprise</:radio>
</.radio_group>Select
<.select
id="country"
name="country"
placeholder="Select country"
options={[
{"United States", "us"},
{"United Kingdom", "uk"},
{"Canada", "ca"}
]}
/>Slider
<.slider id="volume" name="volume" min="0" max="100" value="50" />Range Slider
<.range_slider
id="price-range"
name="price"
min="0"
max="1000"
min_value="100"
max_value="500"
/>Live Select
<.live_select
id="users"
name="user_id"
placeholder="Search users..."
search_event="search_users"
/>Field
<.field>
<:label>Email</:label>
<.input type="email" name="email" />
<:description>We'll never share your email.</:description>
<:error>Invalid email address</:error>
</.field>Input Group
<.input_group>
<:prefix>$</:prefix>
<.input type="number" name="amount" />
<:suffix>.00</:suffix>
</.input_group>
<.input_group>
<:prefix>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
</:prefix>
<.input type="search" name="q" placeholder="Search..." />
</.input_group>Simple Form
<.simple_form for={@form} phx-submit="save">
<.input field={@form[:name]} label="Name" />
<.input field={@form[:email]} type="email" label="Email" />
<:actions>
<.button type="submit">Save</.button>
</:actions>
</.simple_form>Filter Bar
<.filter_bar>
<.input type="search" name="q" placeholder="Search..." />
<.select id="status" name="status" options={@status_options} />
<.button type="submit">Filter</.button>
</.filter_bar>Layout
Card
<.card>
<:header>
<:title>Card Title</:title>
<:description>Card description</:description>
</:header>
Card content goes here
<:footer>
<.button>Action</.button>
</:footer>
</.card>Header
<.header>
<:title>Page Title</:title>
<:subtitle>Optional subtitle</:subtitle>
<:actions>
<.button>Action</.button>
</:actions>
</.header>Table
<.table id="users" rows={@users}>
<:col :let={user} label="Name">{user.name}</:col>
<:col :let={user} label="Email">{user.email}</:col>
<:action :let={user}>
<.button size="sm" variant="ghost">Edit</.button>
</:action>
</.table>Item
<.item>
<:icon>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M10 9H8"/><path d="M16 13H8"/><path d="M16 17H8"/></svg>
</:icon>
<:title>Document Title</:title>
<:description>Description text</:description>
<:action><.button size="sm">View</.button></:action>
</.item>Sidebar
<.sidebar id="main-sidebar">
<:header>
<img src="/logo.svg" alt="Logo" />
</:header>
<:nav>
<.sidebar_item href="/">Home</.sidebar_item>
<.sidebar_item href="/users">Users</.sidebar_item>
</:nav>
<:footer>
<.sidebar_item href="/settings">Settings</.sidebar_item>
</:footer>
</.sidebar>Feedback
Alert
<.alert>Default alert message</.alert>
<.alert variant="destructive">Error message</.alert>
<.alert>
<:title>Heads up!</:title>
You can add components to your app using the CLI.
</.alert>Progress
<.progress value={33} />
<.progress value={66} max={100} />Skeleton
<.skeleton class="h-4 w-[250px]" />
<.skeleton class="h-12 w-12 rounded-full" />Empty
<.empty>
<:icon>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-12 w-12" aria-hidden="true"><polyline points="22 12 16 12 14 15 10 15 8 12 2 12"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/></svg>
</:icon>
<:title>No messages</:title>
<:description>Get started by sending your first message.</:description>
<:action><.button>Send Message</.button></:action>
</.empty>Loading State
<.loading_state>Loading data...</.loading_state>
<.loading_state>
<.spinner />
Please wait...
</.loading_state>Toast
<.toaster />
<!-- Trigger toasts from LiveView -->
<.toast variant="default">Changes saved</.toast>
<.toast variant="destructive">Something went wrong</.toast>Overlay
Dialog
<.dialog id="confirm-dialog">
<:trigger>
<.button>Open Dialog</.button>
</:trigger>
<:title>Confirm Action</:title>
<:description>Are you sure?</:description>
Dialog content here
<:footer>
<.button variant="outline" onclick="this.closest('dialog').close()">
Cancel
</.button>
<.button phx-click="confirm">Confirm</.button>
</:footer>
</.dialog>Dialog JS Commands
import SutraUI.Dialog
<.button phx-click={show_dialog("my-dialog")}>Open</.button>
<.button phx-click={hide_dialog("my-dialog")}>Close</.button>Popover
<.popover id="info-popover">
<:trigger>
<.button variant="outline">Info</.button>
</:trigger>
<:content>
<p>Popover content here</p>
</:content>
</.popover>Tooltip
<.tooltip content="Helpful tip">
<.button>Hover me</.button>
</.tooltip>Dropdown Menu
<.dropdown_menu id="actions-menu">
<:trigger>
<.button variant="outline">Actions</.button>
</:trigger>
<:item phx-click="edit">Edit</:item>
<:item phx-click="duplicate">Duplicate</:item>
<:separator />
<:item phx-click="delete" variant="destructive">Delete</:item>
</.dropdown_menu>Command
<.command id="command-palette">
<:input placeholder="Type a command..." />
<:group heading="Suggestions">
<:item value="calendar">Calendar</:item>
<:item value="search">Search</:item>
<:item value="settings">Settings</:item>
</:group>
</.command>Navigation
Tabs
<.tabs id="settings-tabs" default_value="account">
<:tab value="account">Account</:tab>
<:tab value="password">Password</:tab>
<:tab value="notifications">Notifications</:tab>
<:panel value="account">Account settings...</:panel>
<:panel value="password">Password settings...</:panel>
<:panel value="notifications">Notification preferences...</:panel>
</.tabs>Accordion
<.accordion id="faq">
<:item value="q1" title="What is Sutra UI?">
A Phoenix LiveView component library.
</:item>
<:item value="q2" title="Is it accessible?">
Yes, all components follow WAI-ARIA patterns.
</:item>
</.accordion>Breadcrumb
<.breadcrumb>
<:item href="/">Home</:item>
<:item href="/products">Products</:item>
<:item>Current Page</:item>
</.breadcrumb>Pagination
<.pagination
page={@page}
total_pages={@total_pages}
path={~p"/users"}
/>Nav Pills
<.nav_pills>
<:item href="/dashboard" active>Dashboard</:item>
<:item href="/analytics">Analytics</:item>
<:item href="/reports">Reports</:item>
</.nav_pills>Tab Nav
<.tab_nav>
<:item href={~p"/settings/profile"} active={@tab == :profile}>
Profile
</:item>
<:item href={~p"/settings/account"} active={@tab == :account}>
Account
</:item>
</.tab_nav>Display
Avatar
<.avatar src="/avatar.jpg" alt="User" />
<.avatar src={nil} fallback="JD" />
<.avatar size="sm" src="/avatar.jpg" />
<.avatar size="lg" src="/avatar.jpg" />Carousel
<.carousel id="images">
<:item>
<img src="/image1.jpg" alt="Image 1" />
</:item>
<:item>
<img src="/image2.jpg" alt="Image 2" />
</:item>
<:item>
<img src="/image3.jpg" alt="Image 3" />
</:item>
</.carousel>Theme Switcher
<.theme_switcher />