Components Cheatsheet

View Source

Quick 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

TypeUsage
textGeneral text
emailEmail addresses
passwordPasswords
numberNumeric values
telPhone numbers
urlURLs
searchSearch fields
dateDate picker
timeTime picker
datetime-localDate 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>
  <: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 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 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>

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>
  <: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>
  <: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 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 />