# lostcoords-ui
Rails rendering helpers with semantic HTML, native attributes and browser interactions.
Install and styling: https://ui.lostcoords.com/installation.html
Theming: https://ui.lostcoords.com/theming.html
API JSON: https://ui.lostcoords.com/api.json
Tailwind CSS v4 is required. Install the gem once; the Rails engine exposes all lc_* helpers without per-component imports.
The engine includes a default light and dark theme. Override CSS variables only as needed. Use class: to merge Tailwind utilities, data: and aria: for native attributes. Block helpers capture Rails ERB.
lc_button_to keeps Rails form, method and CSRF semantics. Each host application's lockfile pins its version.
## Theme colors
Override only the roles you need. Soft status backgrounds are generated automatically. Primary controls actions, links, selection and focus.
- `--background`: Page background
- `--foreground`: Main text and headings
- `--card`: Cards and grouped content
- `--card-foreground`: Text on cards
- `--card-input`: Fields on cards; defaults to --input
- `--card-secondary`: Secondary buttons on cards; defaults to --secondary
- `--popover`: Menus, popovers and dialogs
- `--popover-foreground`: Text on menus, popovers and dialogs
- `--primary`: Primary actions, links, selected states and keyboard focus
- `--primary-foreground`: Text and icons on a solid primary background
- `--secondary`: Secondary buttons
- `--secondary-foreground`: Text on secondary buttons
- `--muted`: Subtle backgrounds: badges, code, skeletons, table headers
- `--muted-foreground`: Secondary text, hints and placeholders
- `--accent`: Hovered rows, menu items and inline code
- `--accent-foreground`: Text on accent backgrounds
- `--destructive`: Errors and destructive actions
- `--success`: Successful actions and positive feedback
- `--warning`: Warnings and items needing attention
- `--border`: Dividers and outlines
- `--input`: Input and toggle fills
- `--ring`: Keyboard focus ring; unset, it follows --primary
## lc_checkbox
https://ui.lostcoords.com/components/checkbox.html#lc_checkbox
```ruby
lc_checkbox(label, name: nil, value: "1", checked: false, unchecked_value: "0", hint: nil, card: false, **attributes, &block)
```
Checkboxes: https://ui.lostcoords.com/components/checkbox.html
```erb
<%= lc_stack gap: :related do %>
<%= lc_checkbox "Email me about comments", name: "notify[comments]", checked: true %>
<%= lc_checkbox "Weekly digest", name: "notify[digest]", hint: "A summary every Monday." %>
<%= lc_checkbox "Product news", name: "notify[news]", disabled: true %>
<% end %>
```
## lc_radio
https://ui.lostcoords.com/components/radio.html#lc_radio
```ruby
lc_radio(label, name:, value:, checked: false, hint: nil, card: false, **attributes, &block)
```
Radio group: https://ui.lostcoords.com/components/radio.html
```erb
<%= lc_choice_group legend: "Plan", hint: "You can change plans at any time." do %>
<%= lc_radio "Free", name: "plan", value: "free", checked: true %>
<%= lc_radio "Team", name: "plan", value: "team", hint: "Shared projects and roles." %>
<%= lc_radio "Enterprise", name: "plan", value: "enterprise" %>
<% end %>
```
Cards: https://ui.lostcoords.com/components/radio.html
```erb
<%= lc_choice_group legend: "Plan", class: "w-full max-w-md" do %>
<%= lc_radio "Free", name: "my-component-plan", value: "free", hint: "Up to 3 projects.", card: true %>
<%= lc_radio "Team", name: "my-component-plan", value: "team", hint: "Shared projects and roles.", card: true, checked: true do %>
<%= lc_text "$12 per member, per month", size: :caption, tone: :muted %>
<% end %>
<%= lc_radio "Enterprise", name: "my-component-plan", value: "enterprise", hint: "SSO and audit logs.", card: true %>
<% end %>
```
## lc_switch
https://ui.lostcoords.com/components/switch.html#lc_switch
```ruby
lc_switch(label, name: nil, value: "1", checked: false, unchecked_value: "0", hint: nil, **attributes)
```
Switches: https://ui.lostcoords.com/components/switch.html
```erb
<%= lc_stack gap: :related do %>
<%= lc_switch "Public project", name: "project[public]", checked: true %>
<%= lc_switch "Allow comments", name: "project[comments]", hint: "Members can comment on pages." %>
<% end %>
```
Tabs: https://ui.lostcoords.com/components/tabs.html
```erb
<%= lc_tabs id: "my-component-tabs", label: "Project", class: "w-full" do |tabs| %>
<% tabs.panel "Overview" do %>
<%= lc_text "Pages, members and recent changes." %>
<% end %>
<% tabs.panel "Activity" do %>
<%= lc_text "Nothing new this week.", tone: :muted %>
<% end %>
<% tabs.panel "Settings" do %>
<%= lc_switch "Public project", name: "project[public]" %>
<% end %>
<% end %>
```
Vertical, with manual activation: https://ui.lostcoords.com/components/tabs.html
```erb
<%= lc_tabs id: "my-component-settings", label: "Settings", orientation: :vertical, activation: :manual, class: "w-full" do |tabs| %>
<% tabs.panel "Profile" do %>
<%= lc_text "Name, photo and contact details." %>
<% end %>
<% tabs.panel "Notifications" do %>
<%= lc_switch "Email me about mentions", name: "settings[mentions]" %>
<% end %>
<% tabs.panel "Billing" do %>
<%= lc_text "Plan, invoices and payment method.", tone: :muted %>
<% end %>
<% end %>
```
## lc_choice_group
https://ui.lostcoords.com/components/radio.html#lc_choice_group
```ruby
lc_choice_group(legend:, **options, &block)
```
Radio group: https://ui.lostcoords.com/components/radio.html
```erb
<%= lc_choice_group legend: "Plan", hint: "You can change plans at any time." do %>
<%= lc_radio "Free", name: "plan", value: "free", checked: true %>
<%= lc_radio "Team", name: "plan", value: "team", hint: "Shared projects and roles." %>
<%= lc_radio "Enterprise", name: "plan", value: "enterprise" %>
<% end %>
```
Cards: https://ui.lostcoords.com/components/radio.html
```erb
<%= lc_choice_group legend: "Plan", class: "w-full max-w-md" do %>
<%= lc_radio "Free", name: "my-component-plan", value: "free", hint: "Up to 3 projects.", card: true %>
<%= lc_radio "Team", name: "my-component-plan", value: "team", hint: "Shared projects and roles.", card: true, checked: true do %>
<%= lc_text "$12 per member, per month", size: :caption, tone: :muted %>
<% end %>
<%= lc_radio "Enterprise", name: "my-component-plan", value: "enterprise", hint: "SSO and audit logs.", card: true %>
<% end %>
```
## lc_code_block
https://ui.lostcoords.com/components/code_block.html#lc_code_block
```ruby
lc_code_block(source, id:, language: nil, title: nil, label: nil, max_lines: 10, **attributes, &block)
```
Plain source: https://ui.lostcoords.com/components/code_block.html
```erb
<%= lc_code_block "def hello(name)\n puts name\nend", id: "my-component-ruby", language: :ruby, label: "Ruby greeting", class: "w-full" %>
```
With a filename: https://ui.lostcoords.com/components/code_block.html
```erb
<%= lc_code_block "def hello(name)\n puts name\nend", id: "my-component-file", language: :ruby, title: "app/helpers/greeting_helper.rb", label: "Greeting helper", class: "w-full" %>
```
Collapsible source: https://ui.lostcoords.com/components/code_block.html
```erb
<%= lc_code_block (1..15).map { |number| "puts #{number}" }.join("\n"), id: "my-component-long", language: :ruby, label: "Long Ruby snippet", max_lines: 5, class: "w-full" %>
```
## lc_collapsible
https://ui.lostcoords.com/components/collapsible.html#lc_collapsible
```ruby
lc_collapsible(title: nil, open: false, card: true, summary_class: nil, indicator: :marker, button: nil, **attributes, &block)
```
Expandable content: https://ui.lostcoords.com/components/collapsible.html
```erb
<%= lc_collapsible class: "w-full", title: "Can I use my own colors?" do %>
Yes. Override the default theme values in your application stylesheet.
<% end %>
```
Row summary with a chevron: https://ui.lostcoords.com/components/collapsible.html
```erb
<%= lc_collapsible card: false, indicator: :chevron, class: "w-full max-w-80", summary_class: "rounded-2xl px-3 font-medium hover:bg-accent" do |collapsible| %>
<% collapsible.summary do %>
Language
English
<% end %>
<%= lc_toggle_group label: "Language", value: "en" do %>
<%= lc_toggle_group_item "English", value: "en", selected: true %>
<%= lc_toggle_group_item "日本語", value: "ja" %>
<% end %>
<% end %>
```
Button summary: https://ui.lostcoords.com/components/collapsible.html
```erb
<%= lc_collapsible card: false, button: { variant: :secondary, size: :sm }, summary_class: "w-fit", class: "w-full max-w-80" do |collapsible| %>
<% collapsible.summary do %>
<%= lc_icon "user-plus", options: { "aria-hidden": true } %>
Invite people
<% end %>
<%= lc_field label: "Email", id: "my-component-email" do |field| %>
<%= lc_input name: "email", type: :email, **field %>
<% end %>
<% end %>
```
## lc_copy_button
https://ui.lostcoords.com/components/copy_button.html#lc_copy_button
```ruby
lc_copy_button(label = nil, value: nil, source: nil, copied_label: nil, error_label: nil, reset_after: 2000, icon_only: false, variant: :secondary, size: :md, **attributes)
```
Motion feedback: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_copy_button "Copy link", value: "https://ui.lostcoords.com", copied_label: "Link copied", reset_after: 2500 %>
<%= lc_copy_button "Copy link", value: "https://ui.lostcoords.com", icon_only: true, variant: :ghost %>
```
Labels, icons and disabled controls: https://ui.lostcoords.com/components/copy_button.html
```erb
<%= lc_copy_button value: "https://ui.lostcoords.com", variant: :primary %>
<%= lc_copy_button "Copy link", value: "https://ui.lostcoords.com", copied_label: "Link copied" %>
<%= lc_copy_button "Copy link", value: "https://ui.lostcoords.com", icon_only: true, variant: :ghost %>
<%= lc_copy_button value: "Unavailable", disabled: true %>
```
Copy from an element: https://ui.lostcoords.com/components/copy_button.html
```erb
<%= lc_stack gap: :related, class: "w-full max-w-md" do %>
<%= lc_field label: "Share link", id: "my-component-link" do |field| %>
<%= lc_input value: "https://ui.lostcoords.com", **field %>
<% end %>
<%= lc_copy_button "Copy current link", source: "my-component-link", copied_label: "Link copied", class: "w-full" %>
<%= lc_text "Edit the link, then copy it. The button reads the current value each time.", size: :small, tone: :muted %>
<% end %>
```
Translated labels: https://ui.lostcoords.com/components/copy_button.html
```erb
<% I18n.with_locale(:ja) do %>
<%= lc_copy_button value: "https://ui.lostcoords.com", lang: "ja" %>
<% end %>
<% I18n.with_locale(:es) do %>
<%= lc_copy_button value: "https://ui.lostcoords.com", lang: "es" %>
<% end %>
```
## lc_description_list
https://ui.lostcoords.com/components/description_list.html#lc_description_list
```ruby
lc_description_list(**attributes, &block)
list.item(term, detail = nil, **attributes, &block)
```
Details: https://ui.lostcoords.com/components/description_list.html
```erb
<%= lc_card class: "w-full" do |card| %>
<%= card.header title: "Workspace" %>
<%= lc_description_list do |list| %>
<%= list.item "Owner", "Ada Baker" %>
<%= list.item "Plan" do %>
<%= lc_badge "Team", tone: :primary %>
<% end %>
<%= list.item "Created", "March 4, 2026" %>
<% end %>
<% end %>
```
## lc_dialog
https://ui.lostcoords.com/components/dialog.html#lc_dialog
```ruby
lc_dialog(id:, title:, description: nil, trigger: lc_t("lostcoords.ui.dialog.trigger"), kind: :modal, size: nil, detents: "fit",
close_action: "lc-dialog#close", close_label: nil, title_attributes: {}, description_attributes: {}, **attributes, &block)
dialog.actions(&block)
dialog.footer(**attributes, &block)
dialog.close(label = nil, variant: :secondary, **attributes)
```
Modal: https://ui.lostcoords.com/components/dialog.html
```erb
<%= lc_dialog id: "my-component-dialog", title: "Create project", description: "Projects group pages and members.", trigger: "New project" do |dialog| %>
<% end %>
```
Mobile dialog: https://ui.lostcoords.com/components/dialog.html
```erb
<%= lc_dialog id: "my-component-sheet", title: "Workspace details", trigger: "Open mobile dialog", detents: "fit" do %>
Drag the handle down to dismiss.
<%= lc_field label: "Workspace", id: "my-component-workspace" do |field| %>
<%= lc_input value: "Design studio", **field %>
<% end %>
<% end %>
```
Mobile height options: https://ui.lostcoords.com/components/dialog.html
```erb
<%= lc_dialog id: "my-component-sheet", title: "Notes", detents: "medium large" do %>
<%= lc_textarea name: "notes", rows: 16, aria: { label: "Notes" }, placeholder: "Write something…" %>
<% end %>
```
Compact dialog: https://ui.lostcoords.com/components/dialog.html
```erb
<%= lc_dialog id: "my-component-context", title: "Quick details", trigger: "Open compact dialog", kind: :context do %>
A compact dialog for a short, focused task.
<% end %>
<%= lc_dialog id: "my-component-invite", title: "Invite people", kind: :context do |dialog| %>
<% dialog.trigger { |attrs| lc_button "Invite with your own trigger", variant: :ghost, **attrs } %>
This step marks itself data-dialog-size="md", so the compact dialog widens to 32rem while it shows.
<% end %>
```
Opened by your controller: https://ui.lostcoords.com/components/dialog.html
```erb
<%= lc_button "Show members", variant: :secondary, aria: { haspopup: "dialog", controls: "my-component-members" }, data: { action: "lc-dialog#open" } %>
<%= lc_dialog id: "my-component-members", title: "Members", trigger: false, size: :lg, detents: "large", data: { lc_dialog_target: "dialog" } do |dialog| %>
<%= dialog.actions do %>
<%= lc_button "Invite", size: :sm %>
<% end %>
<% %w[Aiko Ben Chiara Dmitri Emi Farah Goro Hana].each do |name| %>
<%= name %>
<% end %>
<% end %>
```
## lc_confirm_sheet
https://ui.lostcoords.com/components/dialog.html#lc_confirm_sheet
```ruby
lc_confirm_sheet(**attributes)
```
Turbo confirm: https://ui.lostcoords.com/components/dialog.html
```erb
<%# In the layout, once. %>
<%= lc_confirm_sheet %>
<%= lc_button_to "Delete project", "/projects/42", method: :delete, variant: :destructive, form: { data: { turbo_confirm: "Delete this project?", turbo_confirm_description: "Its pages and files are deleted for everyone.", controller: "confirm-demo", action: "confirm-demo#submit" } } %>
<%= lc_button_to "Archive", "/projects/42/archival", form: { data: { turbo_confirm: "Archive this project?", turbo_confirm_accept: "Archive project", controller: "confirm-demo", action: "confirm-demo#submit" } } %>
<%= lc_menu id: "my-component-menu", label: "Membership" do %>
<%= lc_menu_option "Leave project", href: "/projects/42/membership", method: :delete, tone: :destructive, form: { data: { turbo_confirm: "Leave this project?", turbo_confirm_accept: "Leave", controller: "confirm-demo", action: "confirm-demo#submit" } } %>
<% end %>
```
## lc_emoji_picker
https://ui.lostcoords.com/components/emoji.html#lc_emoji_picker
```ruby
lc_emoji_picker(form:, field:, label:, catalog_url:, value: nil, quick: [], recent: [], recent_scope: nil, auto_submit: false, **attributes)
```
Emoji picker: https://ui.lostcoords.com/components/emoji.html
```erb
<%= fields_for :project do |form| %>
<%= lc_emoji_picker form: form, field: :emoji, value: "✨", quick: %w[🥝 🍣 🍜 ☕], label: "Choose an emoji", catalog_url: "/emoji-catalog.html" %>
<% end %>
```
## lc_form_with
https://ui.lostcoords.com/components/field.html#lc_form_with
```ruby
lc_form_with(card: false, padding: :md, gap: nil, **options, &block)
```
Form builder: https://ui.lostcoords.com/components/field.html
```erb
<%= lc_form_with model: DocsProject.invalid_example, url: "#", card: true, class: "w-full max-w-sm" do |form| %>
<%= form.field :name, hint: "Shown to members." %>
<%= form.field :email, as: :email_field, size: :sm, label: "Email (compact)" %>
<%= form.switch :public, hint: "Anyone with the link can view." %>
<%= form.submit "Save project" %>
<% end %>
```
## lc_glass
https://ui.lostcoords.com/components/glass.html#lc_glass
```ruby
lc_glass(shape: :bar, thick: false, as: :div, **attributes, &block)
```
Search bar: https://ui.lostcoords.com/components/glass.html
```erb
<%= lc_glass as: :label, class: "flex w-full max-w-sm items-center gap-related min-h-control-lg px-content" do %>
<%= lc_icon "magnifying-glass", options: { class: "size-5 text-muted-foreground", "aria-hidden": true } %>
<% end %>
```
## lc_icon
https://ui.lostcoords.com/components/button.html#lc_icon
```ruby
lc_icon(name, variant: :outline, options: {}, path_options: {})
```
Custom icons and content: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_button variant: :secondary do %>
<%= lc_icon "arrow-down-tray", options: {
"aria-hidden": true,
"data-icon": "inline-start"
} %>
Download report
<% end %>
<%= lc_button disabled: true, aria: { busy: true } do %>
<%= lc_spinner size: :sm, label: nil,
data: { icon: "inline-start" } %>
Loading report…
<% end %>
```
Button summary: https://ui.lostcoords.com/components/collapsible.html
```erb
<%= lc_collapsible card: false, button: { variant: :secondary, size: :sm }, summary_class: "w-fit", class: "w-full max-w-80" do |collapsible| %>
<% collapsible.summary do %>
<%= lc_icon "user-plus", options: { "aria-hidden": true } %>
Invite people
<% end %>
<%= lc_field label: "Email", id: "my-component-email" do |field| %>
<%= lc_input name: "email", type: :email, **field %>
<% end %>
<% end %>
```
Search bar: https://ui.lostcoords.com/components/glass.html
```erb
<%= lc_glass as: :label, class: "flex w-full max-w-sm items-center gap-related min-h-control-lg px-content" do %>
<%= lc_icon "magnifying-glass", options: { class: "size-5 text-muted-foreground", "aria-hidden": true } %>
<% end %>
```
Settings: https://ui.lostcoords.com/components/list_group.html
```erb
<%= lc_list_section "Sign-in methods", id: "my-component", footnote: "Keep at least one way to sign in.", class: "w-full max-w-md" do %>
<%= lc_list_group do %>
<%= lc_list_row "Email", subtitle: "ada@example.com", icon: "envelope" do %>
<%= lc_button "Change", variant: :secondary, size: :sm %>
<% end %>
<%= lc_list_row "Passkey", subtitle: "Not set up", icon: "key" do %>
<%= lc_button "Add", variant: :secondary, size: :sm %>
<% end %>
<%= lc_list_row "Sign-in alerts", subtitle: "Email me when a new device signs in", icon: "bell", tag: :label, class: "cursor-pointer" do %>
<% end %>
<%= lc_list_row "Recovery codes", icon: "document-text", href: "#recovery-codes" do %>
<%= lc_icon "chevron-right", variant: :mini, options: { class: "size-5 text-muted-foreground rtl:rotate-180", "aria-hidden": true } %>
<% end %>
<%= lc_list_row padded: false do %>
<%= lc_list_item "Delete account", icon: "trash", tag: :button, type: "button", class: "w-full cursor-pointer rounded-[inherit] text-destructive transition-colors hover:bg-accent" %>
<% end %>
<% end %>
<% end %>
```
## lc_stack
https://ui.lostcoords.com/components/foundations.html#lc_stack
```ruby
lc_stack(gap: :content, as: :div, **attributes, &block)
```
Text styles: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_heading "Weekend in Kyoto", level: 2, size: :title %>
<%= lc_heading "Shared expenses", level: 3, size: :heading %>
<%= lc_heading "Dinner with friends", level: 4, size: :subheading %>
<%= lc_text do %>Use lc_stack to keep related content together.<% end %>
<%= lc_text "Add a receipt or a short note for your group.", size: :small, tone: :muted %>
<%= lc_text "Updated a few minutes ago", size: :caption, tone: :muted %>
```
Page rhythm: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_stack gap: :section, class: "w-full max-w-xl" do %>
<%= lc_section title: "Recent expenses", actions: capture { lc_button("Add expense", icon: "plus", size: :sm) } do %>
<%= lc_card do %>
<%= lc_inline class: "flex-nowrap justify-between" do %>
<%= lc_text "Dinner with friends" %>
<%= lc_text "¥8,400", class: "shrink-0 tabular-nums" %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_text "Train tickets" %>
<% end %>
<% end %>
<%= lc_stack as: :section, gap: :heading do %>
<%= lc_section_header do %>
<%= lc_stack gap: :tight do %>
<%= lc_heading "Members" %>
<%= lc_text "Everyone who can see this workspace.", size: :small, tone: :muted %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_inline do %>
<%= lc_avatar "AK", class: "bg-primary" %>
<%= lc_stack gap: :tight do %>
<%= lc_text "Alex Kim" %>
<%= lc_text "Joined today", size: :small, tone: :muted %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
```
Responsive containers: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_container do %>
<%= lc_stack gap: :section do %>
<%= lc_heading "Plan your next trip", level: 2, size: :title %>
<%= lc_section title: "Travel details", level: 3 do %>
<%= lc_card do %>
<%= lc_stack do %>
<%= lc_text "Kyoto weekend", size: :body %>
<%= lc_text "Keep shared costs and travel notes together.", size: :small, tone: :muted %>
<%= lc_inline do %>
<%= lc_button "Invite friends", size: :sm %>
<%= lc_button "View itinerary", variant: :ghost, size: :sm %>
<% end %>
<% end %>
<% end %>
<% end %>
<%= lc_section title: "Shared costs", level: 3 do %>
<%= lc_card do %>
<%= lc_text "No expenses yet", size: :body %>
<% end %>
<% end %>
<% end %>
<% end %>
```
Checkboxes: https://ui.lostcoords.com/components/checkbox.html
```erb
<%= lc_stack gap: :related do %>
<%= lc_checkbox "Email me about comments", name: "notify[comments]", checked: true %>
<%= lc_checkbox "Weekly digest", name: "notify[digest]", hint: "A summary every Monday." %>
<%= lc_checkbox "Product news", name: "notify[news]", disabled: true %>
<% end %>
```
Copy from an element: https://ui.lostcoords.com/components/copy_button.html
```erb
<%= lc_stack gap: :related, class: "w-full max-w-md" do %>
<%= lc_field label: "Share link", id: "my-component-link" do |field| %>
<%= lc_input value: "https://ui.lostcoords.com", **field %>
<% end %>
<%= lc_copy_button "Copy current link", source: "my-component-link", copied_label: "Link copied", class: "w-full" %>
<%= lc_text "Edit the link, then copy it. The button reads the current value each time.", size: :small, tone: :muted %>
<% end %>
```
Empty state: https://ui.lostcoords.com/components/empty_state.html
```erb
<%= lc_empty_state class: "w-full" do %>
<%= lc_icon_badge shape: :circle, tone: :primary, icon: "folder-plus", size: :lg%>
<%= lc_stack gap: :tight, class: "max-w-xs" do %>
<%= lc_heading "No projects yet", level: 3, size: :subheading %>
<%= lc_text "Create a project to get started.", size: :small, tone: :muted %>
<% end %>
<%= lc_button "Create project" %>
<% end %>
```
Grouped controls: https://ui.lostcoords.com/components/field.html
```erb
<%= lc_stack class: "w-full max-w-sm" do %>
<%= lc_fieldset legend: "Split", id: "my-component-split", hint: "Everyone pays the same share unless you change it." do %>
<%= lc_inline do %>
<%= lc_toggle "Equally", active: true %>
<%= lc_toggle "By amount" %>
<%= lc_toggle "By share" %>
<% end %>
<% end %>
<%= lc_stack gap: :related do %>
<%= lc_text "This app can", size: :label, tone: :muted %>
Read your groups
Add expenses
<% end %>
<% end %>
```
Focus a field: https://ui.lostcoords.com/components/kbd.html
```erb
<%= lc_stack gap: :related, class: "w-full max-w-sm" do %>
<%= lc_field label: "Filter projects", id: "my-component-filter" do |field| %>
<%= lc_input name: "q", type: :search, placeholder: "Press / to filter", data: lc_shortcut_data("/"), **field %>
<% end %>
<%= lc_text size: :small, tone: :muted do %>
Press <%= lc_kbd "/" %> to filter, then <%= lc_kbd "escape" %> to clear.
<% end %>
<% end %>
```
Tones: https://ui.lostcoords.com/components/link.html
```erb
<%= lc_stack gap: :related do %>
<%= lc_text do %>Read the <%= lc_link "installation guide", "/installation.html" %> before you start.<% end %>
<%= lc_text size: :small, tone: :muted do %>Questions? <%= lc_link "Contact support", "/components/link.html", tone: :muted %>.<% end %>
<%= lc_text do %>See <%= lc_link "what's new", "/components/link.html", tone: :primary %> in this release.<% end %>
<% end %>
```
Skip link: https://ui.lostcoords.com/components/skip_link.html
```erb
<%= lc_stack gap: :related, class: "items-center" do %>
<%= lc_text "Press Tab on this page: the skip link is the first thing to receive focus.", size: :small, tone: :muted %>
<%= lc_skip_link "#examples", class: "not-sr-only static" %>
<% end %>
```
Switches: https://ui.lostcoords.com/components/switch.html
```erb
<%= lc_stack gap: :related do %>
<%= lc_switch "Public project", name: "project[public]", checked: true %>
<%= lc_switch "Allow comments", name: "project[comments]", hint: "Members can comment on pages." %>
<% end %>
```
## lc_inline
https://ui.lostcoords.com/components/foundations.html#lc_inline
```ruby
lc_inline(gap: :related, as: :div, **attributes, &block)
```
Page rhythm: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_stack gap: :section, class: "w-full max-w-xl" do %>
<%= lc_section title: "Recent expenses", actions: capture { lc_button("Add expense", icon: "plus", size: :sm) } do %>
<%= lc_card do %>
<%= lc_inline class: "flex-nowrap justify-between" do %>
<%= lc_text "Dinner with friends" %>
<%= lc_text "¥8,400", class: "shrink-0 tabular-nums" %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_text "Train tickets" %>
<% end %>
<% end %>
<%= lc_stack as: :section, gap: :heading do %>
<%= lc_section_header do %>
<%= lc_stack gap: :tight do %>
<%= lc_heading "Members" %>
<%= lc_text "Everyone who can see this workspace.", size: :small, tone: :muted %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_inline do %>
<%= lc_avatar "AK", class: "bg-primary" %>
<%= lc_stack gap: :tight do %>
<%= lc_text "Alex Kim" %>
<%= lc_text "Joined today", size: :small, tone: :muted %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
```
Responsive containers: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_container do %>
<%= lc_stack gap: :section do %>
<%= lc_heading "Plan your next trip", level: 2, size: :title %>
<%= lc_section title: "Travel details", level: 3 do %>
<%= lc_card do %>
<%= lc_stack do %>
<%= lc_text "Kyoto weekend", size: :body %>
<%= lc_text "Keep shared costs and travel notes together.", size: :small, tone: :muted %>
<%= lc_inline do %>
<%= lc_button "Invite friends", size: :sm %>
<%= lc_button "View itinerary", variant: :ghost, size: :sm %>
<% end %>
<% end %>
<% end %>
<% end %>
<%= lc_section title: "Shared costs", level: 3 do %>
<%= lc_card do %>
<%= lc_text "No expenses yet", size: :body %>
<% end %>
<% end %>
<% end %>
<% end %>
```
Expanded swap and decorative span: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_inline do %>
<%= lc_button "New entry", icon: "plus", expanded_icon: "x-mark", size: :sm, aria: { expanded: false } %>
<%= lc_button "New entry", icon: "plus", expanded_icon: "x-mark", size: :sm, aria: { expanded: true } %>
Drop a receipt here
<%= lc_button "Browse files", as: :span, size: :sm, aria: { hidden: true } %>
<% end %>
```
Form actions: https://ui.lostcoords.com/components/field.html
```erb
<%= lc_inline class: "justify-end" do %>
<%= lc_button "Cancel", variant: :ghost %>
<%= lc_button "Save changes", type: :submit %>
<% end %>
```
Grouped controls: https://ui.lostcoords.com/components/field.html
```erb
<%= lc_stack class: "w-full max-w-sm" do %>
<%= lc_fieldset legend: "Split", id: "my-component-split", hint: "Everyone pays the same share unless you change it." do %>
<%= lc_inline do %>
<%= lc_toggle "Equally", active: true %>
<%= lc_toggle "By amount" %>
<%= lc_toggle "By share" %>
<% end %>
<% end %>
<%= lc_stack gap: :related do %>
<%= lc_text "This app can", size: :label, tone: :muted %>
Read your groups
Add expenses
<% end %>
<% end %>
```
Filters: https://ui.lostcoords.com/components/toggle.html
```erb
<%= lc_inline role: "group", aria: { label: "Topics" } do %>
<%= lc_toggle "Design", active: true %>
<%= lc_toggle "Writing" %>
<%= lc_toggle "Research" %>
<% end %>
```
Navigation: https://ui.lostcoords.com/components/toggle.html
```erb
<%= lc_inline do %>
<%= lc_toggle "All projects", href: "/components/toggle.html", active: true, size: :sm %>
<%= lc_toggle "Archived", href: "/components/badge.html", size: :sm %>
<% end %>
```
Form values, native radios and reset: https://ui.lostcoords.com/components/toggle_group.html
```erb
```
Tooltips: https://ui.lostcoords.com/components/tooltip.html
```erb
<%= lc_inline gap: :content do %>
<%= lc_tooltip "Copy a link to this page", id: "my-component-copy-tip" do |tip| %>
<%= lc_icon_button "Copy link", icon: "link", **tip %>
<% end %>
<%= lc_tooltip "Only owners can archive", id: "my-component-archive-tip", side: :bottom do |tip| %>
<%= lc_button "Archive", variant: :secondary, **tip %>
<% end %>
<% end %>
```
## lc_container
https://ui.lostcoords.com/components/foundations.html#lc_container
```ruby
lc_container(size: :page, **attributes, &block)
```
Responsive containers: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_container do %>
<%= lc_stack gap: :section do %>
<%= lc_heading "Plan your next trip", level: 2, size: :title %>
<%= lc_section title: "Travel details", level: 3 do %>
<%= lc_card do %>
<%= lc_stack do %>
<%= lc_text "Kyoto weekend", size: :body %>
<%= lc_text "Keep shared costs and travel notes together.", size: :small, tone: :muted %>
<%= lc_inline do %>
<%= lc_button "Invite friends", size: :sm %>
<%= lc_button "View itinerary", variant: :ghost, size: :sm %>
<% end %>
<% end %>
<% end %>
<% end %>
<%= lc_section title: "Shared costs", level: 3 do %>
<%= lc_card do %>
<%= lc_text "No expenses yet", size: :body %>
<% end %>
<% end %>
<% end %>
<% end %>
```
## lc_section
https://ui.lostcoords.com/components/foundations.html#lc_section
```ruby
lc_section(title:, level: 2, actions: nil, **attributes, &block)
```
Page rhythm: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_stack gap: :section, class: "w-full max-w-xl" do %>
<%= lc_section title: "Recent expenses", actions: capture { lc_button("Add expense", icon: "plus", size: :sm) } do %>
<%= lc_card do %>
<%= lc_inline class: "flex-nowrap justify-between" do %>
<%= lc_text "Dinner with friends" %>
<%= lc_text "¥8,400", class: "shrink-0 tabular-nums" %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_text "Train tickets" %>
<% end %>
<% end %>
<%= lc_stack as: :section, gap: :heading do %>
<%= lc_section_header do %>
<%= lc_stack gap: :tight do %>
<%= lc_heading "Members" %>
<%= lc_text "Everyone who can see this workspace.", size: :small, tone: :muted %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_inline do %>
<%= lc_avatar "AK", class: "bg-primary" %>
<%= lc_stack gap: :tight do %>
<%= lc_text "Alex Kim" %>
<%= lc_text "Joined today", size: :small, tone: :muted %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
```
Responsive containers: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_container do %>
<%= lc_stack gap: :section do %>
<%= lc_heading "Plan your next trip", level: 2, size: :title %>
<%= lc_section title: "Travel details", level: 3 do %>
<%= lc_card do %>
<%= lc_stack do %>
<%= lc_text "Kyoto weekend", size: :body %>
<%= lc_text "Keep shared costs and travel notes together.", size: :small, tone: :muted %>
<%= lc_inline do %>
<%= lc_button "Invite friends", size: :sm %>
<%= lc_button "View itinerary", variant: :ghost, size: :sm %>
<% end %>
<% end %>
<% end %>
<% end %>
<%= lc_section title: "Shared costs", level: 3 do %>
<%= lc_card do %>
<%= lc_text "No expenses yet", size: :body %>
<% end %>
<% end %>
<% end %>
<% end %>
```
## lc_section_header
https://ui.lostcoords.com/components/foundations.html#lc_section_header
```ruby
lc_section_header(as: :header, **attributes, &block)
```
Page rhythm: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_stack gap: :section, class: "w-full max-w-xl" do %>
<%= lc_section title: "Recent expenses", actions: capture { lc_button("Add expense", icon: "plus", size: :sm) } do %>
<%= lc_card do %>
<%= lc_inline class: "flex-nowrap justify-between" do %>
<%= lc_text "Dinner with friends" %>
<%= lc_text "¥8,400", class: "shrink-0 tabular-nums" %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_text "Train tickets" %>
<% end %>
<% end %>
<%= lc_stack as: :section, gap: :heading do %>
<%= lc_section_header do %>
<%= lc_stack gap: :tight do %>
<%= lc_heading "Members" %>
<%= lc_text "Everyone who can see this workspace.", size: :small, tone: :muted %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_inline do %>
<%= lc_avatar "AK", class: "bg-primary" %>
<%= lc_stack gap: :tight do %>
<%= lc_text "Alex Kim" %>
<%= lc_text "Joined today", size: :small, tone: :muted %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
```
## lc_list_section
https://ui.lostcoords.com/components/list_group.html#lc_list_section
```ruby
lc_list_section(heading, footnote: nil, level: 2, **attributes, &block)
```
Settings: https://ui.lostcoords.com/components/list_group.html
```erb
<%= lc_list_section "Sign-in methods", id: "my-component", footnote: "Keep at least one way to sign in.", class: "w-full max-w-md" do %>
<%= lc_list_group do %>
<%= lc_list_row "Email", subtitle: "ada@example.com", icon: "envelope" do %>
<%= lc_button "Change", variant: :secondary, size: :sm %>
<% end %>
<%= lc_list_row "Passkey", subtitle: "Not set up", icon: "key" do %>
<%= lc_button "Add", variant: :secondary, size: :sm %>
<% end %>
<%= lc_list_row "Sign-in alerts", subtitle: "Email me when a new device signs in", icon: "bell", tag: :label, class: "cursor-pointer" do %>
<% end %>
<%= lc_list_row "Recovery codes", icon: "document-text", href: "#recovery-codes" do %>
<%= lc_icon "chevron-right", variant: :mini, options: { class: "size-5 text-muted-foreground rtl:rotate-180", "aria-hidden": true } %>
<% end %>
<%= lc_list_row padded: false do %>
<%= lc_list_item "Delete account", icon: "trash", tag: :button, type: "button", class: "w-full cursor-pointer rounded-[inherit] text-destructive transition-colors hover:bg-accent" %>
<% end %>
<% end %>
<% end %>
```
## lc_list_group
https://ui.lostcoords.com/components/list_group.html#lc_list_group
```ruby
lc_list_group(tag: :div, **attributes, &block)
```
Settings: https://ui.lostcoords.com/components/list_group.html
```erb
<%= lc_list_section "Sign-in methods", id: "my-component", footnote: "Keep at least one way to sign in.", class: "w-full max-w-md" do %>
<%= lc_list_group do %>
<%= lc_list_row "Email", subtitle: "ada@example.com", icon: "envelope" do %>
<%= lc_button "Change", variant: :secondary, size: :sm %>
<% end %>
<%= lc_list_row "Passkey", subtitle: "Not set up", icon: "key" do %>
<%= lc_button "Add", variant: :secondary, size: :sm %>
<% end %>
<%= lc_list_row "Sign-in alerts", subtitle: "Email me when a new device signs in", icon: "bell", tag: :label, class: "cursor-pointer" do %>
<% end %>
<%= lc_list_row "Recovery codes", icon: "document-text", href: "#recovery-codes" do %>
<%= lc_icon "chevron-right", variant: :mini, options: { class: "size-5 text-muted-foreground rtl:rotate-180", "aria-hidden": true } %>
<% end %>
<%= lc_list_row padded: false do %>
<%= lc_list_item "Delete account", icon: "trash", tag: :button, type: "button", class: "w-full cursor-pointer rounded-[inherit] text-destructive transition-colors hover:bg-accent" %>
<% end %>
<% end %>
<% end %>
```
Form rows: https://ui.lostcoords.com/components/list_group.html
```erb
<%= lc_list_group class: "w-full max-w-md" do %>
<%= lc_list_field "Description", icon: "pencil", id: "my-component-description" do %>
<%= lc_input plain: true, id: "my-component-description", name: "description", placeholder: "Dinner at Ichiran" %>
<% end %>
<%= lc_list_field "Paid by", icon: "user", tag: :fieldset do %>
<%= lc_toggle "Ada", size: :sm, active: true %>
<%= lc_toggle "Grace", size: :sm %>
<% end %>
<%= lc_list_field "Date", icon: "calendar", id: "my-component-date" do %>
<%= lc_input type: :date, plain: true, id: "my-component-date", name: "date", value: "2026-11-06" %>
<% end %>
<% end %>
```
## lc_list_row
https://ui.lostcoords.com/components/list_group.html#lc_list_row
```ruby
lc_list_row(title = nil, subtitle: nil, icon: nil, href: nil, tag: nil, padded: true, **attributes, &block)
```
Settings: https://ui.lostcoords.com/components/list_group.html
```erb
<%= lc_list_section "Sign-in methods", id: "my-component", footnote: "Keep at least one way to sign in.", class: "w-full max-w-md" do %>
<%= lc_list_group do %>
<%= lc_list_row "Email", subtitle: "ada@example.com", icon: "envelope" do %>
<%= lc_button "Change", variant: :secondary, size: :sm %>
<% end %>
<%= lc_list_row "Passkey", subtitle: "Not set up", icon: "key" do %>
<%= lc_button "Add", variant: :secondary, size: :sm %>
<% end %>
<%= lc_list_row "Sign-in alerts", subtitle: "Email me when a new device signs in", icon: "bell", tag: :label, class: "cursor-pointer" do %>
<% end %>
<%= lc_list_row "Recovery codes", icon: "document-text", href: "#recovery-codes" do %>
<%= lc_icon "chevron-right", variant: :mini, options: { class: "size-5 text-muted-foreground rtl:rotate-180", "aria-hidden": true } %>
<% end %>
<%= lc_list_row padded: false do %>
<%= lc_list_item "Delete account", icon: "trash", tag: :button, type: "button", class: "w-full cursor-pointer rounded-[inherit] text-destructive transition-colors hover:bg-accent" %>
<% end %>
<% end %>
<% end %>
```
## lc_list_field
https://ui.lostcoords.com/components/list_group.html#lc_list_field
```ruby
lc_list_field(label, icon: nil, id: nil, tag: :div, surface: true, **attributes, &block)
```
Form rows: https://ui.lostcoords.com/components/list_group.html
```erb
<%= lc_list_group class: "w-full max-w-md" do %>
<%= lc_list_field "Description", icon: "pencil", id: "my-component-description" do %>
<%= lc_input plain: true, id: "my-component-description", name: "description", placeholder: "Dinner at Ichiran" %>
<% end %>
<%= lc_list_field "Paid by", icon: "user", tag: :fieldset do %>
<%= lc_toggle "Ada", size: :sm, active: true %>
<%= lc_toggle "Grace", size: :sm %>
<% end %>
<%= lc_list_field "Date", icon: "calendar", id: "my-component-date" do %>
<%= lc_input type: :date, plain: true, id: "my-component-date", name: "date", value: "2026-11-06" %>
<% end %>
<% end %>
```
## lc_list_item
https://ui.lostcoords.com/components/list_group.html#lc_list_item
```ruby
lc_list_item(title, subtitle: nil, icon: nil, tag: :div, **attributes, &block)
```
Settings: https://ui.lostcoords.com/components/list_group.html
```erb
<%= lc_list_section "Sign-in methods", id: "my-component", footnote: "Keep at least one way to sign in.", class: "w-full max-w-md" do %>
<%= lc_list_group do %>
<%= lc_list_row "Email", subtitle: "ada@example.com", icon: "envelope" do %>
<%= lc_button "Change", variant: :secondary, size: :sm %>
<% end %>
<%= lc_list_row "Passkey", subtitle: "Not set up", icon: "key" do %>
<%= lc_button "Add", variant: :secondary, size: :sm %>
<% end %>
<%= lc_list_row "Sign-in alerts", subtitle: "Email me when a new device signs in", icon: "bell", tag: :label, class: "cursor-pointer" do %>
<% end %>
<%= lc_list_row "Recovery codes", icon: "document-text", href: "#recovery-codes" do %>
<%= lc_icon "chevron-right", variant: :mini, options: { class: "size-5 text-muted-foreground rtl:rotate-180", "aria-hidden": true } %>
<% end %>
<%= lc_list_row padded: false do %>
<%= lc_list_item "Delete account", icon: "trash", tag: :button, type: "button", class: "w-full cursor-pointer rounded-[inherit] text-destructive transition-colors hover:bg-accent" %>
<% end %>
<% end %>
<% end %>
```
## lc_menu
https://ui.lostcoords.com/components/menu.html#lc_menu
```ruby
lc_menu(id:, label: lc_t("lostcoords.ui.menu.label"), align: :end, trigger: :button, icon: "ellipsis-vertical", trigger_attributes: {}, wrapper_attributes: {}, **attributes, &block)
```
Select trigger: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_menu id: "my-component-menu", label: "Member", align: :start do |menu| %>
<% menu.trigger(class: "min-w-44") { |attrs| lc_select_trigger "All members", **attrs } %>
<%= lc_menu_option "All members", checked: true %>
<%= lc_menu_option "Alex", checked: false %>
<%= lc_menu_option "Sam", checked: false %>
<% end %>
```
Turbo confirm: https://ui.lostcoords.com/components/dialog.html
```erb
<%# In the layout, once. %>
<%= lc_confirm_sheet %>
<%= lc_button_to "Delete project", "/projects/42", method: :delete, variant: :destructive, form: { data: { turbo_confirm: "Delete this project?", turbo_confirm_description: "Its pages and files are deleted for everyone.", controller: "confirm-demo", action: "confirm-demo#submit" } } %>
<%= lc_button_to "Archive", "/projects/42/archival", form: { data: { turbo_confirm: "Archive this project?", turbo_confirm_accept: "Archive project", controller: "confirm-demo", action: "confirm-demo#submit" } } %>
<%= lc_menu id: "my-component-menu", label: "Membership" do %>
<%= lc_menu_option "Leave project", href: "/projects/42/membership", method: :delete, tone: :destructive, form: { data: { turbo_confirm: "Leave this project?", turbo_confirm_accept: "Leave", controller: "confirm-demo", action: "confirm-demo#submit" } } %>
<% end %>
```
Actions: https://ui.lostcoords.com/components/menu.html
```erb
<%= lc_menu id: "my-component-menu", label: "Project actions" do %>
<%= lc_menu_option "Edit project", href: "/components/input.html" %>
<%= lc_menu_option "Duplicate project" %>
<%= lc_menu_option "Archive project", tone: :destructive %>
<% end %>
```
Icon trigger, hints, choices and groups: https://ui.lostcoords.com/components/menu.html
```erb
<%= lc_menu id: "my-component-row-menu", label: "Actions for Alex", trigger: :icon do %>
<%= lc_menu_option "Rename", icon: "pencil" %>
<%= lc_menu_option "Move up", icon: "arrow-up", hint: "Second in the list" %>
<%= lc_menu_option "Copy link" %>
<%= lc_menu_option "Pinned", icon: "star", checkbox: true %>
<%= lc_menu_option "Remove", icon: "trash", href: "/components/menu.html", method: :delete, tone: :destructive %>
<% end %>
<%= lc_menu id: "my-component-currency-menu", label: "Currency", align: :start do |menu| %>
<% menu.trigger { |attrs| lc_select_trigger "Euro", **attrs } %>
<%= lc_menu_group "Suggested", id: "my-component-suggested" do %>
<%= lc_menu_option "Euro", hint: "EUR", leading: tag.span("€"), checked: true %>
<%= lc_menu_option "Japanese yen", hint: "JPY", leading: tag.span("¥"), checked: false %>
<% end %>
<%= lc_menu_group "Other", id: "my-component-other" do %>
<%= lc_menu_option "US dollar", hint: "USD", leading: tag.span("$"), checked: false %>
<% end %>
<% end %>
```
## lc_popover
https://ui.lostcoords.com/components/popover.html#lc_popover
```ruby
lc_popover(id:, label: lc_t("lostcoords.ui.popover.trigger"), title: nil, align: :end, trigger_variant: :secondary, trigger: :button, icon: "ellipsis-vertical", trigger_attributes: {}, wrapper_attributes: {}, **attributes, &block)
```
Anchored content: https://ui.lostcoords.com/components/popover.html
```erb
<%= lc_popover id: "my-component-popover", label: "Project details", title: "Design system" do %>
Updated a moment ago by Alex.
<% end %>
```
Opened from a row: https://ui.lostcoords.com/components/popover.html
```erb
```
## lc_menu_option
https://ui.lostcoords.com/components/menu.html#lc_menu_option
```ruby
lc_menu_option(label = nil, href: nil, tone: :default, icon: nil, leading: nil, hint: nil, checked: nil, checkbox: false, method: nil, params: {}, form: {}, **attributes, &block)
```
Select trigger: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_menu id: "my-component-menu", label: "Member", align: :start do |menu| %>
<% menu.trigger(class: "min-w-44") { |attrs| lc_select_trigger "All members", **attrs } %>
<%= lc_menu_option "All members", checked: true %>
<%= lc_menu_option "Alex", checked: false %>
<%= lc_menu_option "Sam", checked: false %>
<% end %>
```
Split button: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_split_button "Add expense", id: "my-component-menu", icon: "plus", menu_label: "More ways to add" do %>
<%= lc_menu_option "Import a CSV", icon: "arrow-down-tray" %>
<%= lc_menu_option "Scan a receipt", icon: "camera" %>
<% end %>
```
Split button variants and sizes: https://ui.lostcoords.com/components/button.html
```erb
<% [ [ :secondary, :sm ], [ :outline, :md ], [ :ghost, :lg ] ].each do |variant, size| %>
<%= lc_split_button "Export", id: "my-component-#{variant}", variant: variant, size: size, menu_label: "Export options" do %>
<%= lc_menu_option "Export as CSV" %>
<%= lc_menu_option "Export as PDF" %>
<% end %>
<% end %>
```
Turbo confirm: https://ui.lostcoords.com/components/dialog.html
```erb
<%# In the layout, once. %>
<%= lc_confirm_sheet %>
<%= lc_button_to "Delete project", "/projects/42", method: :delete, variant: :destructive, form: { data: { turbo_confirm: "Delete this project?", turbo_confirm_description: "Its pages and files are deleted for everyone.", controller: "confirm-demo", action: "confirm-demo#submit" } } %>
<%= lc_button_to "Archive", "/projects/42/archival", form: { data: { turbo_confirm: "Archive this project?", turbo_confirm_accept: "Archive project", controller: "confirm-demo", action: "confirm-demo#submit" } } %>
<%= lc_menu id: "my-component-menu", label: "Membership" do %>
<%= lc_menu_option "Leave project", href: "/projects/42/membership", method: :delete, tone: :destructive, form: { data: { turbo_confirm: "Leave this project?", turbo_confirm_accept: "Leave", controller: "confirm-demo", action: "confirm-demo#submit" } } %>
<% end %>
```
Actions: https://ui.lostcoords.com/components/menu.html
```erb
<%= lc_menu id: "my-component-menu", label: "Project actions" do %>
<%= lc_menu_option "Edit project", href: "/components/input.html" %>
<%= lc_menu_option "Duplicate project" %>
<%= lc_menu_option "Archive project", tone: :destructive %>
<% end %>
```
Icon trigger, hints, choices and groups: https://ui.lostcoords.com/components/menu.html
```erb
<%= lc_menu id: "my-component-row-menu", label: "Actions for Alex", trigger: :icon do %>
<%= lc_menu_option "Rename", icon: "pencil" %>
<%= lc_menu_option "Move up", icon: "arrow-up", hint: "Second in the list" %>
<%= lc_menu_option "Copy link" %>
<%= lc_menu_option "Pinned", icon: "star", checkbox: true %>
<%= lc_menu_option "Remove", icon: "trash", href: "/components/menu.html", method: :delete, tone: :destructive %>
<% end %>
<%= lc_menu id: "my-component-currency-menu", label: "Currency", align: :start do |menu| %>
<% menu.trigger { |attrs| lc_select_trigger "Euro", **attrs } %>
<%= lc_menu_group "Suggested", id: "my-component-suggested" do %>
<%= lc_menu_option "Euro", hint: "EUR", leading: tag.span("€"), checked: true %>
<%= lc_menu_option "Japanese yen", hint: "JPY", leading: tag.span("¥"), checked: false %>
<% end %>
<%= lc_menu_group "Other", id: "my-component-other" do %>
<%= lc_menu_option "US dollar", hint: "USD", leading: tag.span("$"), checked: false %>
<% end %>
<% end %>
```
## lc_menu_group
https://ui.lostcoords.com/components/menu.html#lc_menu_group
```ruby
lc_menu_group(label, id:, **attributes, &block)
```
Icon trigger, hints, choices and groups: https://ui.lostcoords.com/components/menu.html
```erb
<%= lc_menu id: "my-component-row-menu", label: "Actions for Alex", trigger: :icon do %>
<%= lc_menu_option "Rename", icon: "pencil" %>
<%= lc_menu_option "Move up", icon: "arrow-up", hint: "Second in the list" %>
<%= lc_menu_option "Copy link" %>
<%= lc_menu_option "Pinned", icon: "star", checkbox: true %>
<%= lc_menu_option "Remove", icon: "trash", href: "/components/menu.html", method: :delete, tone: :destructive %>
<% end %>
<%= lc_menu id: "my-component-currency-menu", label: "Currency", align: :start do |menu| %>
<% menu.trigger { |attrs| lc_select_trigger "Euro", **attrs } %>
<%= lc_menu_group "Suggested", id: "my-component-suggested" do %>
<%= lc_menu_option "Euro", hint: "EUR", leading: tag.span("€"), checked: true %>
<%= lc_menu_option "Japanese yen", hint: "JPY", leading: tag.span("¥"), checked: false %>
<% end %>
<%= lc_menu_group "Other", id: "my-component-other" do %>
<%= lc_menu_option "US dollar", hint: "USD", leading: tag.span("$"), checked: false %>
<% end %>
<% end %>
```
## lc_link
https://ui.lostcoords.com/components/link.html#lc_link
```ruby
lc_link(content = nil, url = nil, tone: :inherit, **attributes, &block)
```
Tones: https://ui.lostcoords.com/components/link.html
```erb
<%= lc_stack gap: :related do %>
<%= lc_text do %>Read the <%= lc_link "installation guide", "/installation.html" %> before you start.<% end %>
<%= lc_text size: :small, tone: :muted do %>Questions? <%= lc_link "Contact support", "/components/link.html", tone: :muted %>.<% end %>
<%= lc_text do %>See <%= lc_link "what's new", "/components/link.html", tone: :primary %> in this release.<% end %>
<% end %>
```
## lc_nav_list
https://ui.lostcoords.com/components/nav_list.html#lc_nav_list
```ruby
lc_nav_list(label:, compact: false, layout: :column, indicator: false, **attributes, &block)
nav.link(label = nil, url = nil, icon: nil, current: false, indent: false, **attributes, &block)
nav.group(title, **attributes, &block)
```
Sidebar: https://ui.lostcoords.com/components/nav_list.html
```erb
<%= lc_nav_list label: "Settings", class: "w-full max-w-60" do |nav| %>
<%= nav.group "Workspace" do %>
<%= nav.link "General", "#general", current: true %>
<%= nav.link "Members", "#members" %>
<%= nav.link "Billing", "#billing" %>
<% end %>
<%= nav.group "Account" do %>
<%= nav.link "Profile", "#profile" %>
<%= nav.link "Notifications", "#notifications" %>
<% end %>
<% end %>
```
On this page: https://ui.lostcoords.com/components/nav_list.html
```erb
<%= lc_nav_list label: "On this page", compact: true, class: "w-full max-w-48" do |nav| %>
<%= nav.link "Overview", "#overview", current: true %>
<%= nav.link "Usage", "#usage" %>
<%= nav.link "Sizes", "#sizes", indent: true %>
<%= nav.link "API reference", "#api" %>
<% end %>
```
Row with a sliding indicator: https://ui.lostcoords.com/components/nav_list.html
```erb
<%= lc_nav_list label: "Project", layout: :row, indicator: true, class: "w-full" do |nav| %>
<%= nav.link "Overview", "#overview", icon: "document-text", current: true %>
<%= nav.link "Activity", "#activity", icon: "clock" %>
<%= nav.link "Files", "#files", icon: "paper-clip" %>
<%= nav.link "Settings", "#settings", icon: "cog-6-tooth" %>
<% end %>
```
Dock: https://ui.lostcoords.com/components/nav_list.html
```erb
<%# On phones, fix it to the bottom with your own classes. layout: :responsive is a dock below sm and a row from sm. %>
<%= lc_nav_list label: "Group", layout: :dock, indicator: true, class: lc_glass_class(thick: true, extra: "w-full max-w-sm") do |nav| %>
<%= nav.link "Overview", "#overview", icon: "document-text", current: true %>
<%= nav.link "Members", "#members", icon: "users" %>
<%= nav.link "Activity", "#activity", icon: "clock" %>
<%= nav.link "Stats", "#stats", icon: "chart-bar" %>
<% end %>
```
## lc_pager
https://ui.lostcoords.com/components/pager.html#lc_pager
```ruby
lc_pager(previous: nil, next: nil, label: lc_t("lostcoords.ui.pager.label"), compact: false, **attributes)
```
Pager: https://ui.lostcoords.com/components/pager.html
```erb
<%= lc_pager previous: [ "Installation", "/components/pager.html" ], next: [ "Theming", "/components/pager.html" ], class: "w-full" %>
```
Compact: https://ui.lostcoords.com/components/pager.html
```erb
<%= lc_pager previous: [ "Button", "/components/pager.html" ], next: [ "Card", "/components/pager.html" ], label: "Components", compact: true %>
```
## lc_skip_link
https://ui.lostcoords.com/components/skip_link.html#lc_skip_link
```ruby
lc_skip_link(target = "#main", label: lc_t("lostcoords.ui.skip_link.label"), **attributes)
```
Skip link: https://ui.lostcoords.com/components/skip_link.html
```erb
<%= lc_stack gap: :related, class: "items-center" do %>
<%= lc_text "Press Tab on this page: the skip link is the first thing to receive focus.", size: :small, tone: :muted %>
<%= lc_skip_link "#examples", class: "not-sr-only static" %>
<% end %>
```
## lc_breadcrumb
https://ui.lostcoords.com/components/breadcrumb.html#lc_breadcrumb
```ruby
lc_breadcrumb(items, label: lc_t("lostcoords.ui.breadcrumb.label"), **attributes)
```
Breadcrumb: https://ui.lostcoords.com/components/breadcrumb.html
```erb
<%= lc_breadcrumb [ [ "Projects", "/components/breadcrumb.html" ], [ "Design system", "/components/breadcrumb.html" ], "Settings" ] %>
```
## lc_tabs
https://ui.lostcoords.com/components/tabs.html#lc_tabs
```ruby
lc_tabs(id:, label:, selected: nil, orientation: :horizontal, activation: :automatic, list: {}, **attributes, &block)
tabs.panel(label, value: nil, **attributes, &block)
```
Tabs: https://ui.lostcoords.com/components/tabs.html
```erb
<%= lc_tabs id: "my-component-tabs", label: "Project", class: "w-full" do |tabs| %>
<% tabs.panel "Overview" do %>
<%= lc_text "Pages, members and recent changes." %>
<% end %>
<% tabs.panel "Activity" do %>
<%= lc_text "Nothing new this week.", tone: :muted %>
<% end %>
<% tabs.panel "Settings" do %>
<%= lc_switch "Public project", name: "project[public]" %>
<% end %>
<% end %>
```
Vertical, with manual activation: https://ui.lostcoords.com/components/tabs.html
```erb
<%= lc_tabs id: "my-component-settings", label: "Settings", orientation: :vertical, activation: :manual, class: "w-full" do |tabs| %>
<% tabs.panel "Profile" do %>
<%= lc_text "Name, photo and contact details." %>
<% end %>
<% tabs.panel "Notifications" do %>
<%= lc_switch "Email me about mentions", name: "settings[mentions]" %>
<% end %>
<% tabs.panel "Billing" do %>
<%= lc_text "Plan, invoices and payment method.", tone: :muted %>
<% end %>
<% end %>
```
## lc_button
https://ui.lostcoords.com/components/button.html#lc_button
```ruby
lc_button(content = nil, variant: :primary, tone: :default, size: :md, block: false, icon: nil, icon_position: :start, as: :button, expanded_icon: nil, **attributes, &content_block)
```
Page rhythm: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_stack gap: :section, class: "w-full max-w-xl" do %>
<%= lc_section title: "Recent expenses", actions: capture { lc_button("Add expense", icon: "plus", size: :sm) } do %>
<%= lc_card do %>
<%= lc_inline class: "flex-nowrap justify-between" do %>
<%= lc_text "Dinner with friends" %>
<%= lc_text "¥8,400", class: "shrink-0 tabular-nums" %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_text "Train tickets" %>
<% end %>
<% end %>
<%= lc_stack as: :section, gap: :heading do %>
<%= lc_section_header do %>
<%= lc_stack gap: :tight do %>
<%= lc_heading "Members" %>
<%= lc_text "Everyone who can see this workspace.", size: :small, tone: :muted %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_inline do %>
<%= lc_avatar "AK", class: "bg-primary" %>
<%= lc_stack gap: :tight do %>
<%= lc_text "Alex Kim" %>
<%= lc_text "Joined today", size: :small, tone: :muted %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
```
Responsive containers: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_container do %>
<%= lc_stack gap: :section do %>
<%= lc_heading "Plan your next trip", level: 2, size: :title %>
<%= lc_section title: "Travel details", level: 3 do %>
<%= lc_card do %>
<%= lc_stack do %>
<%= lc_text "Kyoto weekend", size: :body %>
<%= lc_text "Keep shared costs and travel notes together.", size: :small, tone: :muted %>
<%= lc_inline do %>
<%= lc_button "Invite friends", size: :sm %>
<%= lc_button "View itinerary", variant: :ghost, size: :sm %>
<% end %>
<% end %>
<% end %>
<% end %>
<%= lc_section title: "Shared costs", level: 3 do %>
<%= lc_card do %>
<%= lc_text "No expenses yet", size: :body %>
<% end %>
<% end %>
<% end %>
<% end %>
```
Reading content: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_prose do %>
Make room for the trip
A shared plan is easier to follow when each idea has room to breathe. Keep the essentials close and give a new topic a little more space.
Start with one clear decision , name the plan kyoto-weekend, then choose what comes next .
Choose a place to stay.
Set aside time for a slow morning.
Leave an afternoon open.
The best part of a plan is the space it leaves for a surprise.
Ready to begin?
Buttons and other app controls can opt out of reading styles.
<%= lc_button "Create a plan" %>
<% end %>
```
Hover and press: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_button "Hover or press", icon: "plus" %>
<%= lc_button "Secondary", variant: :secondary %>
<%= lc_icon_button "Add item", icon: "plus" %>
```
Title and actions: https://ui.lostcoords.com/components/alert.html
```erb
<%= lc_alert "Your card was declined. Update the payment method to keep the workspace active.", title: "Payment failed" do |alert| %>
<%= alert.actions do %>
<%= lc_button "Update payment", size: :sm %>
<%= lc_button "Dismiss", variant: :ghost, size: :sm %>
<% end %>
<% end %>
```
Default: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_button "Create project" %>
```
Variants: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_button "Primary" %>
<%= lc_button "Secondary", variant: :secondary %>
<%= lc_button "Outline", variant: :outline %>
<%= lc_button "Ghost", variant: :ghost %>
<%= lc_button "Glass", variant: :glass %>
<%= lc_button "Delete", variant: :destructive %>
```
Destructive tone: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_button "Revoke", variant: :ghost, tone: :destructive %>
<%= lc_button "Sign out", variant: :outline, tone: :destructive %>
<%= lc_button "Remove member", variant: :secondary, tone: :destructive %>
<%= lc_button "Delete group", tone: :destructive %>
```
Glass over content: https://ui.lostcoords.com/components/button.html
```erb
Use glass for controls floating over content. Its translucency is subtle on a flat background.
<%= lc_button "Save", variant: :glass, icon: "bookmark" %>
<%= lc_button "Share", variant: :glass, icon: "arrow-up-tray" %>
```
Sizes: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_button "Small", size: :sm %>
<%= lc_button "Default" %>
<%= lc_button "Large", size: :lg %>
```
With an icon: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_button "Create project", icon: "plus" %>
<%= lc_button "Continue", icon: "arrow-right", icon_position: :end, variant: :secondary %>
```
Custom icons and content: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_button variant: :secondary do %>
<%= lc_icon "arrow-down-tray", options: {
"aria-hidden": true,
"data-icon": "inline-start"
} %>
Download report
<% end %>
<%= lc_button disabled: true, aria: { busy: true } do %>
<%= lc_spinner size: :sm, label: nil,
data: { icon: "inline-start" } %>
Loading report…
<% end %>
```
Loading: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_button disabled: true, aria: { busy: true } do %>
<%= lc_spinner size: :sm, label: nil, data: { icon: "inline-start" } %>
Saving…
<% end %>
```
Disabled: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_button "Unavailable", disabled: true %>
```
Expanded swap and decorative span: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_inline do %>
<%= lc_button "New entry", icon: "plus", expanded_icon: "x-mark", size: :sm, aria: { expanded: false } %>
<%= lc_button "New entry", icon: "plus", expanded_icon: "x-mark", size: :sm, aria: { expanded: true } %>
Drop a receipt here
<%= lc_button "Browse files", as: :span, size: :sm, aria: { hidden: true } %>
<% end %>
```
Default: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card class: "w-full" do |card| %>
<%= card.header title: "Project notes", description: "Keep related content together." do %>
<%= lc_button "Edit", variant: :secondary, size: :sm %>
<% end %>
<%= card.content do %>
<%= lc_text "Notes, links and files for the launch." %>
<% end %>
<%= card.footer do %>
<%= lc_button "Archive", variant: :ghost %>
<%= lc_button "Share" %>
<% end %>
<% end %>
```
Custom spacing: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card class: "w-full [--lc-inset:var(--spacing-section)]" do |card| %>
<%= card.header title: "Welcome", description: "Padding and the gaps between parts both follow --lc-inset." %>
<%= card.footer do %>
<%= lc_button "Get started" %>
<% end %>
<% end %>
```
With form controls: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card class: "@container w-full" do |card| %>
<%= card.header title: "Project settings" %>
<%= card.content do %>
<%= lc_field label: "Project name", id: "my-component-name" do |field| %>
<%= lc_input name: "project[name]", value: "Design system", **field %>
<% end %>
<% end %>
<%= card.footer do %>
<%= lc_button "Save changes" %>
<% end %>
<% end %>
```
Modal: https://ui.lostcoords.com/components/dialog.html
```erb
<%= lc_dialog id: "my-component-dialog", title: "Create project", description: "Projects group pages and members.", trigger: "New project" do |dialog| %>
<% end %>
```
Compact dialog: https://ui.lostcoords.com/components/dialog.html
```erb
<%= lc_dialog id: "my-component-context", title: "Quick details", trigger: "Open compact dialog", kind: :context do %>
A compact dialog for a short, focused task.
<% end %>
<%= lc_dialog id: "my-component-invite", title: "Invite people", kind: :context do |dialog| %>
<% dialog.trigger { |attrs| lc_button "Invite with your own trigger", variant: :ghost, **attrs } %>
This step marks itself data-dialog-size="md", so the compact dialog widens to 32rem while it shows.
<% end %>
```
Opened by your controller: https://ui.lostcoords.com/components/dialog.html
```erb
<%= lc_button "Show members", variant: :secondary, aria: { haspopup: "dialog", controls: "my-component-members" }, data: { action: "lc-dialog#open" } %>
<%= lc_dialog id: "my-component-members", title: "Members", trigger: false, size: :lg, detents: "large", data: { lc_dialog_target: "dialog" } do |dialog| %>
<%= dialog.actions do %>
<%= lc_button "Invite", size: :sm %>
<% end %>
<% %w[Aiko Ben Chiara Dmitri Emi Farah Goro Hana].each do |name| %>
<%= name %>
<% end %>
<% end %>
```
Empty state: https://ui.lostcoords.com/components/empty_state.html
```erb
<%= lc_empty_state class: "w-full" do %>
<%= lc_icon_badge shape: :circle, tone: :primary, icon: "folder-plus", size: :lg%>
<%= lc_stack gap: :tight, class: "max-w-xs" do %>
<%= lc_heading "No projects yet", level: 3, size: :subheading %>
<%= lc_text "Create a project to get started.", size: :small, tone: :muted %>
<% end %>
<%= lc_button "Create project" %>
<% end %>
```
Form actions: https://ui.lostcoords.com/components/field.html
```erb
<%= lc_inline class: "justify-end" do %>
<%= lc_button "Cancel", variant: :ghost %>
<%= lc_button "Save changes", type: :submit %>
<% end %>
```
Settings: https://ui.lostcoords.com/components/list_group.html
```erb
<%= lc_list_section "Sign-in methods", id: "my-component", footnote: "Keep at least one way to sign in.", class: "w-full max-w-md" do %>
<%= lc_list_group do %>
<%= lc_list_row "Email", subtitle: "ada@example.com", icon: "envelope" do %>
<%= lc_button "Change", variant: :secondary, size: :sm %>
<% end %>
<%= lc_list_row "Passkey", subtitle: "Not set up", icon: "key" do %>
<%= lc_button "Add", variant: :secondary, size: :sm %>
<% end %>
<%= lc_list_row "Sign-in alerts", subtitle: "Email me when a new device signs in", icon: "bell", tag: :label, class: "cursor-pointer" do %>
<% end %>
<%= lc_list_row "Recovery codes", icon: "document-text", href: "#recovery-codes" do %>
<%= lc_icon "chevron-right", variant: :mini, options: { class: "size-5 text-muted-foreground rtl:rotate-180", "aria-hidden": true } %>
<% end %>
<%= lc_list_row padded: false do %>
<%= lc_list_item "Delete account", icon: "trash", tag: :button, type: "button", class: "w-full cursor-pointer rounded-[inherit] text-destructive transition-colors hover:bg-accent" %>
<% end %>
<% end %>
<% end %>
```
Over dialogs and sticky headers: https://ui.lostcoords.com/components/toast.html
```erb
<%# In an app, render the region once in the layout and append toasts with turbo_stream.append. %>
<%= lc_toast_region id: "my-component-toasts" %>
<%= lc_toast "Project saved." %>
<%= lc_button "Save project", data: { controller: "toast-demo", action: "toast-demo#show", toast_demo_template_value: "my-component-toast", toast_demo_region_value: "my-component-toasts" } %>
```
Centred, at the top on phones: https://ui.lostcoords.com/components/toast.html
```erb
<%# Centred at the bottom, and at the top on phones, clear of a bottom tab bar. %>
<%= lc_toast_region id: "my-component-toasts", placement: :bottom_center, mobile_placement: :top_center %>
<%= lc_toast "Expense added." %>
<%= lc_button "Add expense", data: { controller: "toast-demo", action: "toast-demo#show", toast_demo_template_value: "my-component-toast", toast_demo_region_value: "my-component-toasts" } %>
```
Form values, native radios and reset: https://ui.lostcoords.com/components/toggle_group.html
```erb
```
Tooltips: https://ui.lostcoords.com/components/tooltip.html
```erb
<%= lc_inline gap: :content do %>
<%= lc_tooltip "Copy a link to this page", id: "my-component-copy-tip" do |tip| %>
<%= lc_icon_button "Copy link", icon: "link", **tip %>
<% end %>
<%= lc_tooltip "Only owners can archive", id: "my-component-archive-tip", side: :bottom do |tip| %>
<%= lc_button "Archive", variant: :secondary, **tip %>
<% end %>
<% end %>
```
## lc_button_link_to
https://ui.lostcoords.com/components/button.html#lc_button_link_to
```ruby
lc_button_link_to(content = nil, url = nil, variant: :primary, tone: :default, size: :md, block: false, icon: nil, icon_position: :start, **attributes, &content_block)
```
As a link: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_button_link_to "Browse components", "/components/button.html", variant: :secondary %>
```
## lc_button_to
https://ui.lostcoords.com/components/button.html#lc_button_to
```ruby
lc_button_to(content = nil, url = nil, variant: :primary, tone: :default, size: :md, block: false, icon: nil, icon_position: :start, **attributes, &content_block)
```
HTTP actions: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_button_to "Archive project", "/projects/42", method: :delete, variant: :destructive, form: { data: { turbo_confirm: "Archive this project?" } } %>
```
Turbo confirm: https://ui.lostcoords.com/components/dialog.html
```erb
<%# In the layout, once. %>
<%= lc_confirm_sheet %>
<%= lc_button_to "Delete project", "/projects/42", method: :delete, variant: :destructive, form: { data: { turbo_confirm: "Delete this project?", turbo_confirm_description: "Its pages and files are deleted for everyone.", controller: "confirm-demo", action: "confirm-demo#submit" } } %>
<%= lc_button_to "Archive", "/projects/42/archival", form: { data: { turbo_confirm: "Archive this project?", turbo_confirm_accept: "Archive project", controller: "confirm-demo", action: "confirm-demo#submit" } } %>
<%= lc_menu id: "my-component-menu", label: "Membership" do %>
<%= lc_menu_option "Leave project", href: "/projects/42/membership", method: :delete, tone: :destructive, form: { data: { turbo_confirm: "Leave this project?", turbo_confirm_accept: "Leave", controller: "confirm-demo", action: "confirm-demo#submit" } } %>
<% end %>
```
## lc_select_trigger
https://ui.lostcoords.com/components/button.html#lc_select_trigger
```ruby
lc_select_trigger(label = nil, size: :md, block: false, **attributes, &content)
```
Select trigger: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_menu id: "my-component-menu", label: "Member", align: :start do |menu| %>
<% menu.trigger(class: "min-w-44") { |attrs| lc_select_trigger "All members", **attrs } %>
<%= lc_menu_option "All members", checked: true %>
<%= lc_menu_option "Alex", checked: false %>
<%= lc_menu_option "Sam", checked: false %>
<% end %>
```
Icon trigger, hints, choices and groups: https://ui.lostcoords.com/components/menu.html
```erb
<%= lc_menu id: "my-component-row-menu", label: "Actions for Alex", trigger: :icon do %>
<%= lc_menu_option "Rename", icon: "pencil" %>
<%= lc_menu_option "Move up", icon: "arrow-up", hint: "Second in the list" %>
<%= lc_menu_option "Copy link" %>
<%= lc_menu_option "Pinned", icon: "star", checkbox: true %>
<%= lc_menu_option "Remove", icon: "trash", href: "/components/menu.html", method: :delete, tone: :destructive %>
<% end %>
<%= lc_menu id: "my-component-currency-menu", label: "Currency", align: :start do |menu| %>
<% menu.trigger { |attrs| lc_select_trigger "Euro", **attrs } %>
<%= lc_menu_group "Suggested", id: "my-component-suggested" do %>
<%= lc_menu_option "Euro", hint: "EUR", leading: tag.span("€"), checked: true %>
<%= lc_menu_option "Japanese yen", hint: "JPY", leading: tag.span("¥"), checked: false %>
<% end %>
<%= lc_menu_group "Other", id: "my-component-other" do %>
<%= lc_menu_option "US dollar", hint: "USD", leading: tag.span("$"), checked: false %>
<% end %>
<% end %>
```
## lc_split_button
https://ui.lostcoords.com/components/button.html#lc_split_button
```ruby
lc_split_button(label, id:, href: nil, menu_label: lc_t("lostcoords.ui.menu.label"), variant: :primary, tone: :default, size: :md,
icon: nil, icon_position: :start, block: false, align: :end, action: {}, toggle: {}, menu: {}, **attributes, &items)
```
Split button: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_split_button "Add expense", id: "my-component-menu", icon: "plus", menu_label: "More ways to add" do %>
<%= lc_menu_option "Import a CSV", icon: "arrow-down-tray" %>
<%= lc_menu_option "Scan a receipt", icon: "camera" %>
<% end %>
```
Split button variants and sizes: https://ui.lostcoords.com/components/button.html
```erb
<% [ [ :secondary, :sm ], [ :outline, :md ], [ :ghost, :lg ] ].each do |variant, size| %>
<%= lc_split_button "Export", id: "my-component-#{variant}", variant: variant, size: size, menu_label: "Export options" do %>
<%= lc_menu_option "Export as CSV" %>
<%= lc_menu_option "Export as PDF" %>
<% end %>
<% end %>
```
## lc_icon_button
https://ui.lostcoords.com/components/button.html#lc_icon_button
```ruby
lc_icon_button(label, icon: nil, size: :md, shape: :circle, variant: :ghost, tone: :default, **attributes, &content)
```
Hover and press: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_button "Hover or press", icon: "plus" %>
<%= lc_button "Secondary", variant: :secondary %>
<%= lc_icon_button "Add item", icon: "plus" %>
```
Icon buttons: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_icon_button "Add project", icon: "plus" %>
<%= lc_icon_button "Settings", icon: "cog-6-tooth", shape: :square %>
<%= lc_icon_button "Search", icon: "magnifying-glass", size: :sm %>
<%= lc_icon_button "Close", icon: "x-mark", size: :lg %>
<%= lc_icon_button_link_to "Back to buttons", "/components/button.html", icon: "chevron-left", shape: :square %>
<%= lc_icon_button "Account", size: :lg do %>AL <% end %>
<%= lc_icon_button_to "Reload buttons", "/components/button.html", icon: "arrow-path", method: :get, form: { class: "contents" } %>
<%= lc_icon_button "Edit", icon: "pencil", variant: :secondary %>
<%= lc_icon_button "Delete file", icon: "trash", variant: :outline, tone: :destructive %>
```
Tooltips: https://ui.lostcoords.com/components/tooltip.html
```erb
<%= lc_inline gap: :content do %>
<%= lc_tooltip "Copy a link to this page", id: "my-component-copy-tip" do |tip| %>
<%= lc_icon_button "Copy link", icon: "link", **tip %>
<% end %>
<%= lc_tooltip "Only owners can archive", id: "my-component-archive-tip", side: :bottom do |tip| %>
<%= lc_button "Archive", variant: :secondary, **tip %>
<% end %>
<% end %>
```
## lc_icon_button_link_to
https://ui.lostcoords.com/components/button.html#lc_icon_button_link_to
```ruby
lc_icon_button_link_to(label, url, icon: nil, size: :md, shape: :circle, variant: :ghost, tone: :default, **attributes, &content)
```
Icon buttons: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_icon_button "Add project", icon: "plus" %>
<%= lc_icon_button "Settings", icon: "cog-6-tooth", shape: :square %>
<%= lc_icon_button "Search", icon: "magnifying-glass", size: :sm %>
<%= lc_icon_button "Close", icon: "x-mark", size: :lg %>
<%= lc_icon_button_link_to "Back to buttons", "/components/button.html", icon: "chevron-left", shape: :square %>
<%= lc_icon_button "Account", size: :lg do %>AL <% end %>
<%= lc_icon_button_to "Reload buttons", "/components/button.html", icon: "arrow-path", method: :get, form: { class: "contents" } %>
<%= lc_icon_button "Edit", icon: "pencil", variant: :secondary %>
<%= lc_icon_button "Delete file", icon: "trash", variant: :outline, tone: :destructive %>
```
## lc_icon_button_to
https://ui.lostcoords.com/components/button.html#lc_icon_button_to
```ruby
lc_icon_button_to(label, url, icon: nil, size: :md, shape: :circle, variant: :ghost, tone: :default, **attributes, &content)
```
Icon buttons: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_icon_button "Add project", icon: "plus" %>
<%= lc_icon_button "Settings", icon: "cog-6-tooth", shape: :square %>
<%= lc_icon_button "Search", icon: "magnifying-glass", size: :sm %>
<%= lc_icon_button "Close", icon: "x-mark", size: :lg %>
<%= lc_icon_button_link_to "Back to buttons", "/components/button.html", icon: "chevron-left", shape: :square %>
<%= lc_icon_button "Account", size: :lg do %>AL <% end %>
<%= lc_icon_button_to "Reload buttons", "/components/button.html", icon: "arrow-path", method: :get, form: { class: "contents" } %>
<%= lc_icon_button "Edit", icon: "pencil", variant: :secondary %>
<%= lc_icon_button "Delete file", icon: "trash", variant: :outline, tone: :destructive %>
```
## lc_badge
https://ui.lostcoords.com/components/badge.html#lc_badge
```ruby
lc_badge(content = nil, tone: :neutral, shape: :rounded, **attributes, &block)
```
Tones: https://ui.lostcoords.com/components/badge.html
```erb
<%= lc_badge "Draft" %>
<%= lc_badge "Published", tone: :primary %>
<%= lc_badge "Complete", tone: :success %>
<%= lc_badge "Needs attention", tone: :warning %>
<%= lc_badge "Failed", tone: :destructive %>
```
Pill status: https://ui.lostcoords.com/components/badge.html
```erb
<%= lc_badge "On track", tone: :primary, shape: :pill %>
<%= lc_badge "Pending", shape: :pill %>
<%= lc_badge "3 errors", tone: :destructive, shape: :pill %>
```
Details: https://ui.lostcoords.com/components/description_list.html
```erb
<%= lc_card class: "w-full" do |card| %>
<%= card.header title: "Workspace" %>
<%= lc_description_list do |list| %>
<%= list.item "Owner", "Ada Baker" %>
<%= list.item "Plan" do %>
<%= lc_badge "Team", tone: :primary %>
<% end %>
<%= list.item "Created", "March 4, 2026" %>
<% end %>
<% end %>
```
## lc_icon_badge
https://ui.lostcoords.com/components/icon_badge.html#lc_icon_badge
```ruby
lc_icon_badge(content = nil, icon: nil, size: :md, shape: :square, tone: :neutral, **attributes, &block)
```
Empty state: https://ui.lostcoords.com/components/empty_state.html
```erb
<%= lc_empty_state class: "w-full" do %>
<%= lc_icon_badge shape: :circle, tone: :primary, icon: "folder-plus", size: :lg%>
<%= lc_stack gap: :tight, class: "max-w-xs" do %>
<%= lc_heading "No projects yet", level: 3, size: :subheading %>
<%= lc_text "Create a project to get started.", size: :small, tone: :muted %>
<% end %>
<%= lc_button "Create project" %>
<% end %>
```
Shapes and sizes: https://ui.lostcoords.com/components/icon_badge.html
```erb
<%= lc_icon_badge icon: "folder", size: :sm %>
<%= lc_icon_badge icon: "folder" %>
<%= lc_icon_badge icon: "document-text", size: :lg %>
<%= lc_icon_badge icon: "document-text", size: :xl %>
<%= lc_icon_badge "🍜", aria: { hidden: true } %>
<%= lc_icon_badge "🍜", size: 7, shape: :plain, aria: { hidden: true } %>
```
Round icons and tones: https://ui.lostcoords.com/components/icon_badge.html
```erb
<%= lc_icon_badge shape: :circle, size: :sm, icon: "sparkles", tone: :primary%>
<%= lc_icon_badge shape: :circle, icon: "user-plus", tone: :neutral, size: :lg%>
```
## lc_avatar
https://ui.lostcoords.com/components/avatar.html#lc_avatar
```ruby
lc_avatar(content = nil, src: nil, alt: nil, size: :md, ink: false, linked: false, as: :span, **attributes, &block)
```
Page rhythm: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_stack gap: :section, class: "w-full max-w-xl" do %>
<%= lc_section title: "Recent expenses", actions: capture { lc_button("Add expense", icon: "plus", size: :sm) } do %>
<%= lc_card do %>
<%= lc_inline class: "flex-nowrap justify-between" do %>
<%= lc_text "Dinner with friends" %>
<%= lc_text "¥8,400", class: "shrink-0 tabular-nums" %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_text "Train tickets" %>
<% end %>
<% end %>
<%= lc_stack as: :section, gap: :heading do %>
<%= lc_section_header do %>
<%= lc_stack gap: :tight do %>
<%= lc_heading "Members" %>
<%= lc_text "Everyone who can see this workspace.", size: :small, tone: :muted %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_inline do %>
<%= lc_avatar "AK", class: "bg-primary" %>
<%= lc_stack gap: :tight do %>
<%= lc_text "Alex Kim" %>
<%= lc_text "Joined today", size: :small, tone: :muted %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
```
Initials and images: https://ui.lostcoords.com/components/avatar.html
```erb
<%= lc_avatar "AL", ink: true, class: "bg-accent", aria: { label: "Alex Lee" } %>
<%= lc_avatar "SK", size: :lg, ink: true, class: "bg-success-soft", aria: { label: "Sam Kim" } %>
<%= lc_avatar "JR", ink: true, class: "bg-warning-soft", aria: { label: "Jamie Rivera" } %>
<%= lc_avatar "MK", ink: true, class: "bg-destructive-soft", aria: { label: "Morgan Kim" } %>
```
Sizes: https://ui.lostcoords.com/components/avatar.html
```erb
<% [ :xs, :sm, 7, :md, 11, :lg, :xl, :xxl ].each do |size| %>
<%= lc_avatar "AL", size: size, ink: true, class: "bg-accent", aria: { label: "Alex Lee (#{size})" } %>
<% end %>
```
Avatar groups: https://ui.lostcoords.com/components/avatar.html
```erb
<%= lc_avatar_stack aria: { label: "Alex, Sam and Jamie" } do %>
<%= lc_avatar "AL", ink: true, class: "bg-success-soft" %>
<%= lc_avatar "SK", ink: true, class: "bg-warning-soft" %>
<%= lc_avatar "JR", ink: true, class: "bg-destructive-soft" %>
<% end %>
```
## lc_avatar_stack
https://ui.lostcoords.com/components/avatar.html#lc_avatar_stack
```ruby
lc_avatar_stack(compact: false, row: {}, **attributes, &block)
```
Avatar groups: https://ui.lostcoords.com/components/avatar.html
```erb
<%= lc_avatar_stack aria: { label: "Alex, Sam and Jamie" } do %>
<%= lc_avatar "AL", ink: true, class: "bg-success-soft" %>
<%= lc_avatar "SK", ink: true, class: "bg-warning-soft" %>
<%= lc_avatar "JR", ink: true, class: "bg-destructive-soft" %>
<% end %>
```
## lc_card
https://ui.lostcoords.com/components/card.html#lc_card
```ruby
lc_card(href: nil, interactive: false, padding: :md, as: :div, **attributes, &block)
card.header(title: nil, description: nil, level: 3, **attributes, &actions)
card.title(content = nil, level: 3, **attributes, &block)
card.description(content = nil, **attributes, &block)
card.content(**attributes, &block)
card.footer(**attributes, &block)
```
Page rhythm: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_stack gap: :section, class: "w-full max-w-xl" do %>
<%= lc_section title: "Recent expenses", actions: capture { lc_button("Add expense", icon: "plus", size: :sm) } do %>
<%= lc_card do %>
<%= lc_inline class: "flex-nowrap justify-between" do %>
<%= lc_text "Dinner with friends" %>
<%= lc_text "¥8,400", class: "shrink-0 tabular-nums" %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_text "Train tickets" %>
<% end %>
<% end %>
<%= lc_stack as: :section, gap: :heading do %>
<%= lc_section_header do %>
<%= lc_stack gap: :tight do %>
<%= lc_heading "Members" %>
<%= lc_text "Everyone who can see this workspace.", size: :small, tone: :muted %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_inline do %>
<%= lc_avatar "AK", class: "bg-primary" %>
<%= lc_stack gap: :tight do %>
<%= lc_text "Alex Kim" %>
<%= lc_text "Joined today", size: :small, tone: :muted %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
```
Responsive containers: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_container do %>
<%= lc_stack gap: :section do %>
<%= lc_heading "Plan your next trip", level: 2, size: :title %>
<%= lc_section title: "Travel details", level: 3 do %>
<%= lc_card do %>
<%= lc_stack do %>
<%= lc_text "Kyoto weekend", size: :body %>
<%= lc_text "Keep shared costs and travel notes together.", size: :small, tone: :muted %>
<%= lc_inline do %>
<%= lc_button "Invite friends", size: :sm %>
<%= lc_button "View itinerary", variant: :ghost, size: :sm %>
<% end %>
<% end %>
<% end %>
<% end %>
<%= lc_section title: "Shared costs", level: 3 do %>
<%= lc_card do %>
<%= lc_text "No expenses yet", size: :body %>
<% end %>
<% end %>
<% end %>
<% end %>
```
Default: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card class: "w-full" do |card| %>
<%= card.header title: "Project notes", description: "Keep related content together." do %>
<%= lc_button "Edit", variant: :secondary, size: :sm %>
<% end %>
<%= card.content do %>
<%= lc_text "Notes, links and files for the launch." %>
<% end %>
<%= card.footer do %>
<%= lc_button "Archive", variant: :ghost %>
<%= lc_button "Share" %>
<% end %>
<% end %>
```
Compact: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card padding: :sm, class: "w-full" do |card| %>
<%= card.header title: "Compact card", description: "Padding and gaps tighten together." %>
<%= lc_text "A compact summary.", size: :small %>
<% end %>
```
Linked card: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card href: "/components/card.html", class: "w-full" do |card| %>
<%= card.header title: "Design system", description: "Open the project." %>
<% end %>
```
Custom spacing: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card class: "w-full [--lc-inset:var(--spacing-section)]" do |card| %>
<%= card.header title: "Welcome", description: "Padding and the gaps between parts both follow --lc-inset." %>
<%= card.footer do %>
<%= lc_button "Get started" %>
<% end %>
<% end %>
```
Edge-to-edge content: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card padding: :none, class: "w-full" do %>
<% [ [ "Design system", "Active" ], [ "Marketing site", "Draft" ] ].each do |name, status| %>
<%= lc_text name %>
<%= lc_text status, size: :small, tone: :muted %>
<% end %>
<% end %>
```
With form controls: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card class: "@container w-full" do |card| %>
<%= card.header title: "Project settings" %>
<%= card.content do %>
<%= lc_field label: "Project name", id: "my-component-name" do |field| %>
<%= lc_input name: "project[name]", value: "Design system", **field %>
<% end %>
<% end %>
<%= card.footer do %>
<%= lc_button "Save changes" %>
<% end %>
<% end %>
```
Validation feedback: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card class: "w-full" do |card| %>
<%= card.content do %>
<%= lc_alert "Choose a unique project name.", tone: :destructive %>
<%= lc_field label: "Project name", id: "my-component-name", error: "This name is already taken." do |field| %>
<%= lc_input name: "project[name]", value: "Design system", **field %>
<% end %>
<% end %>
<% end %>
```
Details: https://ui.lostcoords.com/components/description_list.html
```erb
<%= lc_card class: "w-full" do |card| %>
<%= card.header title: "Workspace" %>
<%= lc_description_list do |list| %>
<%= list.item "Owner", "Ada Baker" %>
<%= list.item "Plan" do %>
<%= lc_badge "Team", tone: :primary %>
<% end %>
<%= list.item "Created", "March 4, 2026" %>
<% end %>
<% end %>
```
## lc_empty_state
https://ui.lostcoords.com/components/empty_state.html#lc_empty_state
```ruby
lc_empty_state(**attributes, &block)
```
Empty state: https://ui.lostcoords.com/components/empty_state.html
```erb
<%= lc_empty_state class: "w-full" do %>
<%= lc_icon_badge shape: :circle, tone: :primary, icon: "folder-plus", size: :lg%>
<%= lc_stack gap: :tight, class: "max-w-xs" do %>
<%= lc_heading "No projects yet", level: 3, size: :subheading %>
<%= lc_text "Create a project to get started.", size: :small, tone: :muted %>
<% end %>
<%= lc_button "Create project" %>
<% end %>
```
## lc_spinner
https://ui.lostcoords.com/components/spinner.html#lc_spinner
```ruby
lc_spinner(size: :md, label: lc_t("lostcoords.ui.spinner.label"), **attributes)
```
Custom icons and content: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_button variant: :secondary do %>
<%= lc_icon "arrow-down-tray", options: {
"aria-hidden": true,
"data-icon": "inline-start"
} %>
Download report
<% end %>
<%= lc_button disabled: true, aria: { busy: true } do %>
<%= lc_spinner size: :sm, label: nil,
data: { icon: "inline-start" } %>
Loading report…
<% end %>
```
Loading: https://ui.lostcoords.com/components/button.html
```erb
<%= lc_button disabled: true, aria: { busy: true } do %>
<%= lc_spinner size: :sm, label: nil, data: { icon: "inline-start" } %>
Saving…
<% end %>
```
Sizes and labels: https://ui.lostcoords.com/components/spinner.html
```erb
<%= lc_spinner size: :sm %>
<%= lc_spinner label: "Loading projects" %>
<%= lc_spinner size: :lg %>
```
## lc_skeleton
https://ui.lostcoords.com/components/skeleton.html#lc_skeleton
```ruby
lc_skeleton(**attributes)
```
Placeholder: https://ui.lostcoords.com/components/skeleton.html
```erb
<%= lc_skeleton class: "h-5 w-48" %>
<%= lc_skeleton class: "h-4 w-full" %>
<%= lc_skeleton class: "h-4 w-3/4" %>
```
## lc_alert
https://ui.lostcoords.com/components/alert.html#lc_alert
```ruby
lc_alert(message = nil, title: nil, tone: :destructive, **attributes, &block)
alert.actions(**attributes, &block)
```
Error: https://ui.lostcoords.com/components/alert.html
```erb
<%= lc_alert "That name is already taken." %>
```
Success: https://ui.lostcoords.com/components/alert.html
```erb
<%= lc_alert "Changes saved.", tone: :success %>
```
Title and actions: https://ui.lostcoords.com/components/alert.html
```erb
<%= lc_alert "Your card was declined. Update the payment method to keep the workspace active.", title: "Payment failed" do |alert| %>
<%= alert.actions do %>
<%= lc_button "Update payment", size: :sm %>
<%= lc_button "Dismiss", variant: :ghost, size: :sm %>
<% end %>
<% end %>
```
Validation feedback: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card class: "w-full" do |card| %>
<%= card.content do %>
<%= lc_alert "Choose a unique project name.", tone: :destructive %>
<%= lc_field label: "Project name", id: "my-component-name", error: "This name is already taken." do |field| %>
<%= lc_input name: "project[name]", value: "Design system", **field %>
<% end %>
<% end %>
<% end %>
```
## lc_prose
https://ui.lostcoords.com/components/foundations.html#lc_prose
```ruby
lc_prose(**attributes, &block)
```
Reading content: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_prose do %>
Make room for the trip
A shared plan is easier to follow when each idea has room to breathe. Keep the essentials close and give a new topic a little more space.
Start with one clear decision , name the plan kyoto-weekend, then choose what comes next .
Choose a place to stay.
Set aside time for a slow morning.
Leave an afternoon open.
The best part of a plan is the space it leaves for a surprise.
Ready to begin?
Buttons and other app controls can opt out of reading styles.
<%= lc_button "Create a plan" %>
<% end %>
```
Japanese reading: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_prose lang: "ja" do %>
旅の計画に、少しの余白を。
みんなで予定を考えるときは、大切なことから順番に決めていきましょう。読みやすい行間と段落の間隔が、長い文章をたどる手助けになります。
最初に決めておきたいこと
集合する場所と時間
みんなで分ける費用
自由に過ごす時間
予定が変わったら、グループにひとこと 。少しの共有で、旅がもっと気軽になります。
何もしない時間も、旅の楽しみのひとつです。
<% end %>
```
## lc_search
https://ui.lostcoords.com/components/search.html#lc_search
```ruby
lc_search(label:, src: nil, param: "q", placeholder: label, trigger: lc_t("lostcoords.ui.search.trigger"), empty: lc_t("lostcoords.ui.search.empty"), prompt: nil,
shortcut: "mod+k", id: "lc-search", **attributes, &block)
```
Filtered in the browser: https://ui.lostcoords.com/components/search.html
```erb
<%# Rows rendered in the block are filtered in the browser. Pass src: to have your server answer each query instead. %>
<%= lc_search label: "Search the workspace", placeholder: "Search projects and people…", empty: "Nothing matches %{query}", id: "my-component", shortcut: nil do %>
<%= lc_search_group "Projects" do %>
<%= lc_search_result "Fieldwork", "#fieldwork", detail: "A quieter identity for an outdoor journal.", icon: "sun", keywords: "brand identity" %>
<%= lc_search_result "Sunday House", "#sunday-house", detail: "A welcoming home for a neighborhood bakery.", icon: "home", keywords: "website" %>
<% end %>
<%= lc_search_group "People" do %>
<%= lc_search_result "Alex Lee", "#alex-lee", detail: "Designer", icon: "user" %>
<%= lc_search_result "Sam Kim", "#sam-kim", detail: "Developer", icon: "user" %>
<% end %>
<% end %>
```
## lc_search_group
https://ui.lostcoords.com/components/search.html#lc_search_group
```ruby
lc_search_group(title, **attributes, &block)
```
Filtered in the browser: https://ui.lostcoords.com/components/search.html
```erb
<%# Rows rendered in the block are filtered in the browser. Pass src: to have your server answer each query instead. %>
<%= lc_search label: "Search the workspace", placeholder: "Search projects and people…", empty: "Nothing matches %{query}", id: "my-component", shortcut: nil do %>
<%= lc_search_group "Projects" do %>
<%= lc_search_result "Fieldwork", "#fieldwork", detail: "A quieter identity for an outdoor journal.", icon: "sun", keywords: "brand identity" %>
<%= lc_search_result "Sunday House", "#sunday-house", detail: "A welcoming home for a neighborhood bakery.", icon: "home", keywords: "website" %>
<% end %>
<%= lc_search_group "People" do %>
<%= lc_search_result "Alex Lee", "#alex-lee", detail: "Designer", icon: "user" %>
<%= lc_search_result "Sam Kim", "#sam-kim", detail: "Developer", icon: "user" %>
<% end %>
<% end %>
```
## lc_search_result
https://ui.lostcoords.com/components/search.html#lc_search_result
```ruby
lc_search_result(title, url, detail: nil, icon: nil, keywords: nil, **attributes, &block)
```
Filtered in the browser: https://ui.lostcoords.com/components/search.html
```erb
<%# Rows rendered in the block are filtered in the browser. Pass src: to have your server answer each query instead. %>
<%= lc_search label: "Search the workspace", placeholder: "Search projects and people…", empty: "Nothing matches %{query}", id: "my-component", shortcut: nil do %>
<%= lc_search_group "Projects" do %>
<%= lc_search_result "Fieldwork", "#fieldwork", detail: "A quieter identity for an outdoor journal.", icon: "sun", keywords: "brand identity" %>
<%= lc_search_result "Sunday House", "#sunday-house", detail: "A welcoming home for a neighborhood bakery.", icon: "home", keywords: "website" %>
<% end %>
<%= lc_search_group "People" do %>
<%= lc_search_result "Alex Lee", "#alex-lee", detail: "Designer", icon: "user" %>
<%= lc_search_result "Sam Kim", "#sam-kim", detail: "Developer", icon: "user" %>
<% end %>
<% end %>
```
## lc_sheet
https://ui.lostcoords.com/components/dialog.html#lc_sheet
```ruby
lc_sheet(tag: :div, anchored: false, detents: "fit", handle: false, size: nil, **attributes, &block)
```
Popover sheet: https://ui.lostcoords.com/components/dialog.html
```erb
Filters
<%= lc_sheet id: "my-component-filters", popover: "auto", role: "dialog", aria: { labelledby: "my-component-filters-title" },
class: lc_glass_class(shape: :picker, extra: "sm:m-auto sm:w-80 sm:rounded-3xl text-foreground") do %>
<%= lc_heading "Filters", id: "my-component-filters-title", size: :title %>
A popover on desktop, a sheet you can swipe away on phones.
Done
<% end %>
```
## lc_input
https://ui.lostcoords.com/components/input.html#lc_input
```ruby
lc_input(name: nil, value: nil, type: :text, size: :md, plain: false, **attributes)
```
With form controls: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card class: "@container w-full" do |card| %>
<%= card.header title: "Project settings" %>
<%= card.content do %>
<%= lc_field label: "Project name", id: "my-component-name" do |field| %>
<%= lc_input name: "project[name]", value: "Design system", **field %>
<% end %>
<% end %>
<%= card.footer do %>
<%= lc_button "Save changes" %>
<% end %>
<% end %>
```
Validation feedback: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card class: "w-full" do |card| %>
<%= card.content do %>
<%= lc_alert "Choose a unique project name.", tone: :destructive %>
<%= lc_field label: "Project name", id: "my-component-name", error: "This name is already taken." do |field| %>
<%= lc_input name: "project[name]", value: "Design system", **field %>
<% end %>
<% end %>
<% end %>
```
Button summary: https://ui.lostcoords.com/components/collapsible.html
```erb
<%= lc_collapsible card: false, button: { variant: :secondary, size: :sm }, summary_class: "w-fit", class: "w-full max-w-80" do |collapsible| %>
<% collapsible.summary do %>
<%= lc_icon "user-plus", options: { "aria-hidden": true } %>
Invite people
<% end %>
<%= lc_field label: "Email", id: "my-component-email" do |field| %>
<%= lc_input name: "email", type: :email, **field %>
<% end %>
<% end %>
```
Copy from an element: https://ui.lostcoords.com/components/copy_button.html
```erb
<%= lc_stack gap: :related, class: "w-full max-w-md" do %>
<%= lc_field label: "Share link", id: "my-component-link" do |field| %>
<%= lc_input value: "https://ui.lostcoords.com", **field %>
<% end %>
<%= lc_copy_button "Copy current link", source: "my-component-link", copied_label: "Link copied", class: "w-full" %>
<%= lc_text "Edit the link, then copy it. The button reads the current value each time.", size: :small, tone: :muted %>
<% end %>
```
Modal: https://ui.lostcoords.com/components/dialog.html
```erb
<%= lc_dialog id: "my-component-dialog", title: "Create project", description: "Projects group pages and members.", trigger: "New project" do |dialog| %>
<% end %>
```
Mobile dialog: https://ui.lostcoords.com/components/dialog.html
```erb
<%= lc_dialog id: "my-component-sheet", title: "Workspace details", trigger: "Open mobile dialog", detents: "fit" do %>
Drag the handle down to dismiss.
<%= lc_field label: "Workspace", id: "my-component-workspace" do |field| %>
<%= lc_input value: "Design studio", **field %>
<% end %>
<% end %>
```
Label and hint: https://ui.lostcoords.com/components/field.html
```erb
<%= lc_field label: "Project name", id: "my-component-name", hint: "A short, memorable name.", class: "w-full max-w-sm" do |field| %>
<%= lc_input name: "project[name]", **field %>
<% end %>
```
Validation: https://ui.lostcoords.com/components/field.html
```erb
<%= lc_field label: "Email address", id: "my-component-email", error: "Enter a valid email address.", class: "w-full max-w-sm" do |field| %>
<%= lc_input name: "email", type: :email, value: "alex@", **field %>
<% end %>
```
Sizes: https://ui.lostcoords.com/components/input.html
```erb
<%= lc_input name: "title", placeholder: "Small", size: :sm, class: "max-w-sm", aria: { label: "Small input" } %>
<%= lc_input name: "title", placeholder: "Default", class: "max-w-sm", aria: { label: "Default input" } %>
<%= lc_input name: "title", placeholder: "Large", size: :lg, class: "max-w-sm", aria: { label: "Large input" } %>
```
Disabled and read-only: https://ui.lostcoords.com/components/input.html
```erb
<%= lc_input value: "Read-only value", readonly: true, class: "max-w-sm", aria: { label: "Read-only input" } %>
<%= lc_input placeholder: "Disabled", disabled: true, class: "max-w-sm", aria: { label: "Disabled input" } %>
```
Focus a field: https://ui.lostcoords.com/components/kbd.html
```erb
<%= lc_stack gap: :related, class: "w-full max-w-sm" do %>
<%= lc_field label: "Filter projects", id: "my-component-filter" do |field| %>
<%= lc_input name: "q", type: :search, placeholder: "Press / to filter", data: lc_shortcut_data("/"), **field %>
<% end %>
<%= lc_text size: :small, tone: :muted do %>
Press <%= lc_kbd "/" %> to filter, then <%= lc_kbd "escape" %> to clear.
<% end %>
<% end %>
```
Form rows: https://ui.lostcoords.com/components/list_group.html
```erb
<%= lc_list_group class: "w-full max-w-md" do %>
<%= lc_list_field "Description", icon: "pencil", id: "my-component-description" do %>
<%= lc_input plain: true, id: "my-component-description", name: "description", placeholder: "Dinner at Ichiran" %>
<% end %>
<%= lc_list_field "Paid by", icon: "user", tag: :fieldset do %>
<%= lc_toggle "Ada", size: :sm, active: true %>
<%= lc_toggle "Grace", size: :sm %>
<% end %>
<%= lc_list_field "Date", icon: "calendar", id: "my-component-date" do %>
<%= lc_input type: :date, plain: true, id: "my-component-date", name: "date", value: "2026-11-06" %>
<% end %>
<% end %>
```
## lc_textarea
https://ui.lostcoords.com/components/textarea.html#lc_textarea
```ruby
lc_textarea(content = nil, name: nil, **attributes, &block)
```
Mobile height options: https://ui.lostcoords.com/components/dialog.html
```erb
<%= lc_dialog id: "my-component-sheet", title: "Notes", detents: "medium large" do %>
<%= lc_textarea name: "notes", rows: 16, aria: { label: "Notes" }, placeholder: "Write something…" %>
<% end %>
```
Textarea: https://ui.lostcoords.com/components/textarea.html
```erb
<%= lc_textarea "A place for your notes.", name: "notes", rows: 4, class: "max-w-sm", aria: { label: "Notes" } %>
```
## lc_select
https://ui.lostcoords.com/components/select.html#lc_select
```ruby
lc_select(options = nil, name: nil, selected: nil, size: :md, **attributes, &block)
```
Native select: https://ui.lostcoords.com/components/select.html
```erb
<%= lc_select [["Design", "design"], ["Engineering", "engineering"]], name: "team", selected: "design", class: "max-w-sm", aria: { label: "Team" } %>
```
## lc_field
https://ui.lostcoords.com/components/field.html#lc_field
```ruby
lc_field(label:, id:, hint: nil, error: nil, size: :md, **attributes, &block)
```
With form controls: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card class: "@container w-full" do |card| %>
<%= card.header title: "Project settings" %>
<%= card.content do %>
<%= lc_field label: "Project name", id: "my-component-name" do |field| %>
<%= lc_input name: "project[name]", value: "Design system", **field %>
<% end %>
<% end %>
<%= card.footer do %>
<%= lc_button "Save changes" %>
<% end %>
<% end %>
```
Validation feedback: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card class: "w-full" do |card| %>
<%= card.content do %>
<%= lc_alert "Choose a unique project name.", tone: :destructive %>
<%= lc_field label: "Project name", id: "my-component-name", error: "This name is already taken." do |field| %>
<%= lc_input name: "project[name]", value: "Design system", **field %>
<% end %>
<% end %>
<% end %>
```
Button summary: https://ui.lostcoords.com/components/collapsible.html
```erb
<%= lc_collapsible card: false, button: { variant: :secondary, size: :sm }, summary_class: "w-fit", class: "w-full max-w-80" do |collapsible| %>
<% collapsible.summary do %>
<%= lc_icon "user-plus", options: { "aria-hidden": true } %>
Invite people
<% end %>
<%= lc_field label: "Email", id: "my-component-email" do |field| %>
<%= lc_input name: "email", type: :email, **field %>
<% end %>
<% end %>
```
Copy from an element: https://ui.lostcoords.com/components/copy_button.html
```erb
<%= lc_stack gap: :related, class: "w-full max-w-md" do %>
<%= lc_field label: "Share link", id: "my-component-link" do |field| %>
<%= lc_input value: "https://ui.lostcoords.com", **field %>
<% end %>
<%= lc_copy_button "Copy current link", source: "my-component-link", copied_label: "Link copied", class: "w-full" %>
<%= lc_text "Edit the link, then copy it. The button reads the current value each time.", size: :small, tone: :muted %>
<% end %>
```
Modal: https://ui.lostcoords.com/components/dialog.html
```erb
<%= lc_dialog id: "my-component-dialog", title: "Create project", description: "Projects group pages and members.", trigger: "New project" do |dialog| %>
<% end %>
```
Mobile dialog: https://ui.lostcoords.com/components/dialog.html
```erb
<%= lc_dialog id: "my-component-sheet", title: "Workspace details", trigger: "Open mobile dialog", detents: "fit" do %>
Drag the handle down to dismiss.
<%= lc_field label: "Workspace", id: "my-component-workspace" do |field| %>
<%= lc_input value: "Design studio", **field %>
<% end %>
<% end %>
```
Label and hint: https://ui.lostcoords.com/components/field.html
```erb
<%= lc_field label: "Project name", id: "my-component-name", hint: "A short, memorable name.", class: "w-full max-w-sm" do |field| %>
<%= lc_input name: "project[name]", **field %>
<% end %>
```
Validation: https://ui.lostcoords.com/components/field.html
```erb
<%= lc_field label: "Email address", id: "my-component-email", error: "Enter a valid email address.", class: "w-full max-w-sm" do |field| %>
<%= lc_input name: "email", type: :email, value: "alex@", **field %>
<% end %>
```
Rails forms: https://ui.lostcoords.com/components/field.html
```erb
<%= form_with scope: :project, url: "#", class: "w-full max-w-sm" do |form| %>
<%= lc_field label: "Project name", id: form.field_id(:name), hint: "Works with Rails form builders." do |field| %>
<%= form.text_field :name, **field, class: lc_input_class %>
<% end %>
<% end %>
```
Focus a field: https://ui.lostcoords.com/components/kbd.html
```erb
<%= lc_stack gap: :related, class: "w-full max-w-sm" do %>
<%= lc_field label: "Filter projects", id: "my-component-filter" do |field| %>
<%= lc_input name: "q", type: :search, placeholder: "Press / to filter", data: lc_shortcut_data("/"), **field %>
<% end %>
<%= lc_text size: :small, tone: :muted do %>
Press <%= lc_kbd "/" %> to filter, then <%= lc_kbd "escape" %> to clear.
<% end %>
<% end %>
```
## lc_fieldset
https://ui.lostcoords.com/components/field.html#lc_fieldset
```ruby
lc_fieldset(legend:, id: nil, hint: nil, error: nil, size: :md, **attributes, &block)
```
Grouped controls: https://ui.lostcoords.com/components/field.html
```erb
<%= lc_stack class: "w-full max-w-sm" do %>
<%= lc_fieldset legend: "Split", id: "my-component-split", hint: "Everyone pays the same share unless you change it." do %>
<%= lc_inline do %>
<%= lc_toggle "Equally", active: true %>
<%= lc_toggle "By amount" %>
<%= lc_toggle "By share" %>
<% end %>
<% end %>
<%= lc_stack gap: :related do %>
<%= lc_text "This app can", size: :label, tone: :muted %>
Read your groups
Add expenses
<% end %>
<% end %>
```
## lc_toggle_group
https://ui.lostcoords.com/components/toggle_group.html#lc_toggle_group
```ruby
lc_toggle_group(label:, name: nil, value: nil, as: :div, variant: :segmented, size: :md, **attributes, &block)
```
Row summary with a chevron: https://ui.lostcoords.com/components/collapsible.html
```erb
<%= lc_collapsible card: false, indicator: :chevron, class: "w-full max-w-80", summary_class: "rounded-2xl px-3 font-medium hover:bg-accent" do |collapsible| %>
<% collapsible.summary do %>
Language
English
<% end %>
<%= lc_toggle_group label: "Language", value: "en" do %>
<%= lc_toggle_group_item "English", value: "en", selected: true %>
<%= lc_toggle_group_item "日本語", value: "ja" %>
<% end %>
<% end %>
```
Mutually exclusive choices: https://ui.lostcoords.com/components/toggle_group.html
```erb
<%= lc_toggle_group label: "View", value: "month" do %>
<%= lc_toggle_group_item "Week", value: "week" %>
<%= lc_toggle_group_item "Month", value: "month", selected: true %>
<%= lc_toggle_group_item "Year", value: "year" %>
<% end %>
```
Navigation links: https://ui.lostcoords.com/components/toggle_group.html
```erb
<%= lc_toggle_group label: "Period", as: :nav do %>
<%= lc_toggle_group_item "Month", href: "/components/toggle_group.html", current: true %>
<%= lc_toggle_group_item "Quarter", href: "/components/toggle.html" %>
<%= lc_toggle_group_item "Year", href: "/components/tabs.html" %>
<% end %>
```
Wrapping pills: https://ui.lostcoords.com/components/toggle_group.html
```erb
<%= lc_toggle_group label: "Category", name: "category", value: "", variant: :pills do %>
<%= lc_toggle_group_item "Leave unchanged", value: "" %>
<%= lc_toggle_group_item "Food", value: "food" %>
<%= lc_toggle_group_item "Transport", value: "transport" %>
<%= lc_toggle_group_item "Lodging", value: "lodging" %>
<% end %>
```
Form values, native radios and reset: https://ui.lostcoords.com/components/toggle_group.html
```erb
```
## lc_toggle_group_item
https://ui.lostcoords.com/components/toggle_group.html#lc_toggle_group_item
```ruby
lc_toggle_group_item(label = nil, value: nil, selected: nil, checked: nil, href: nil, current: nil, input: {}, **attributes, &block)
```
Row summary with a chevron: https://ui.lostcoords.com/components/collapsible.html
```erb
<%= lc_collapsible card: false, indicator: :chevron, class: "w-full max-w-80", summary_class: "rounded-2xl px-3 font-medium hover:bg-accent" do |collapsible| %>
<% collapsible.summary do %>
Language
English
<% end %>
<%= lc_toggle_group label: "Language", value: "en" do %>
<%= lc_toggle_group_item "English", value: "en", selected: true %>
<%= lc_toggle_group_item "日本語", value: "ja" %>
<% end %>
<% end %>
```
Mutually exclusive choices: https://ui.lostcoords.com/components/toggle_group.html
```erb
<%= lc_toggle_group label: "View", value: "month" do %>
<%= lc_toggle_group_item "Week", value: "week" %>
<%= lc_toggle_group_item "Month", value: "month", selected: true %>
<%= lc_toggle_group_item "Year", value: "year" %>
<% end %>
```
Navigation links: https://ui.lostcoords.com/components/toggle_group.html
```erb
<%= lc_toggle_group label: "Period", as: :nav do %>
<%= lc_toggle_group_item "Month", href: "/components/toggle_group.html", current: true %>
<%= lc_toggle_group_item "Quarter", href: "/components/toggle.html" %>
<%= lc_toggle_group_item "Year", href: "/components/tabs.html" %>
<% end %>
```
Wrapping pills: https://ui.lostcoords.com/components/toggle_group.html
```erb
<%= lc_toggle_group label: "Category", name: "category", value: "", variant: :pills do %>
<%= lc_toggle_group_item "Leave unchanged", value: "" %>
<%= lc_toggle_group_item "Food", value: "food" %>
<%= lc_toggle_group_item "Transport", value: "transport" %>
<%= lc_toggle_group_item "Lodging", value: "lodging" %>
<% end %>
```
Form values, native radios and reset: https://ui.lostcoords.com/components/toggle_group.html
```erb
```
## lc_toggle
https://ui.lostcoords.com/components/toggle.html#lc_toggle
```ruby
lc_toggle(label = nil, active: false, ghost: false, size: :md, href: nil, name: nil, value: nil, input: {}, **attributes, &block)
```
Grouped controls: https://ui.lostcoords.com/components/field.html
```erb
<%= lc_stack class: "w-full max-w-sm" do %>
<%= lc_fieldset legend: "Split", id: "my-component-split", hint: "Everyone pays the same share unless you change it." do %>
<%= lc_inline do %>
<%= lc_toggle "Equally", active: true %>
<%= lc_toggle "By amount" %>
<%= lc_toggle "By share" %>
<% end %>
<% end %>
<%= lc_stack gap: :related do %>
<%= lc_text "This app can", size: :label, tone: :muted %>
Read your groups
Add expenses
<% end %>
<% end %>
```
Form rows: https://ui.lostcoords.com/components/list_group.html
```erb
<%= lc_list_group class: "w-full max-w-md" do %>
<%= lc_list_field "Description", icon: "pencil", id: "my-component-description" do %>
<%= lc_input plain: true, id: "my-component-description", name: "description", placeholder: "Dinner at Ichiran" %>
<% end %>
<%= lc_list_field "Paid by", icon: "user", tag: :fieldset do %>
<%= lc_toggle "Ada", size: :sm, active: true %>
<%= lc_toggle "Grace", size: :sm %>
<% end %>
<%= lc_list_field "Date", icon: "calendar", id: "my-component-date" do %>
<%= lc_input type: :date, plain: true, id: "my-component-date", name: "date", value: "2026-11-06" %>
<% end %>
<% end %>
```
Filters: https://ui.lostcoords.com/components/toggle.html
```erb
<%= lc_inline role: "group", aria: { label: "Topics" } do %>
<%= lc_toggle "Design", active: true %>
<%= lc_toggle "Writing" %>
<%= lc_toggle "Research" %>
<% end %>
```
Navigation: https://ui.lostcoords.com/components/toggle.html
```erb
<%= lc_inline do %>
<%= lc_toggle "All projects", href: "/components/toggle.html", active: true, size: :sm %>
<%= lc_toggle "Archived", href: "/components/badge.html", size: :sm %>
<% end %>
```
Disabled and ghost: https://ui.lostcoords.com/components/toggle.html
```erb
<%= lc_toggle "Unavailable", disabled: true %>
<%= lc_toggle "Add filter", ghost: true %>
```
Form values, native radios and reset: https://ui.lostcoords.com/components/toggle_group.html
```erb
```
## lc_table
https://ui.lostcoords.com/components/table.html#lc_table
```ruby
lc_table(**attributes, &block)
```
Records: https://ui.lostcoords.com/components/table.html
```erb
<%= lc_table do %>
Recent activity
Project Status Members
WariWari Active 4
Personal site Active 1
<% end %>
```
## lc_toast
https://ui.lostcoords.com/components/toast.html#lc_toast
```ruby
lc_toast(message = nil, tone: :success, timeout: 4000, **attributes, &block)
```
Brief feedback: https://ui.lostcoords.com/components/toast.html
```erb
<%= lc_toast "Project saved.", timeout: 0 %>
```
Over dialogs and sticky headers: https://ui.lostcoords.com/components/toast.html
```erb
<%# In an app, render the region once in the layout and append toasts with turbo_stream.append. %>
<%= lc_toast_region id: "my-component-toasts" %>
<%= lc_toast "Project saved." %>
<%= lc_button "Save project", data: { controller: "toast-demo", action: "toast-demo#show", toast_demo_template_value: "my-component-toast", toast_demo_region_value: "my-component-toasts" } %>
```
Centred, at the top on phones: https://ui.lostcoords.com/components/toast.html
```erb
<%# Centred at the bottom, and at the top on phones, clear of a bottom tab bar. %>
<%= lc_toast_region id: "my-component-toasts", placement: :bottom_center, mobile_placement: :top_center %>
<%= lc_toast "Expense added." %>
<%= lc_button "Add expense", data: { controller: "toast-demo", action: "toast-demo#show", toast_demo_template_value: "my-component-toast", toast_demo_region_value: "my-component-toasts" } %>
```
## lc_toast_region
https://ui.lostcoords.com/components/toast.html#lc_toast_region
```ruby
lc_toast_region(placement: :bottom_end, mobile_placement: nil, **attributes, &block)
```
Over dialogs and sticky headers: https://ui.lostcoords.com/components/toast.html
```erb
<%# In an app, render the region once in the layout and append toasts with turbo_stream.append. %>
<%= lc_toast_region id: "my-component-toasts" %>
<%= lc_toast "Project saved." %>
<%= lc_button "Save project", data: { controller: "toast-demo", action: "toast-demo#show", toast_demo_template_value: "my-component-toast", toast_demo_region_value: "my-component-toasts" } %>
```
Centred, at the top on phones: https://ui.lostcoords.com/components/toast.html
```erb
<%# Centred at the bottom, and at the top on phones, clear of a bottom tab bar. %>
<%= lc_toast_region id: "my-component-toasts", placement: :bottom_center, mobile_placement: :top_center %>
<%= lc_toast "Expense added." %>
<%= lc_button "Add expense", data: { controller: "toast-demo", action: "toast-demo#show", toast_demo_template_value: "my-component-toast", toast_demo_region_value: "my-component-toasts" } %>
```
## lc_tooltip
https://ui.lostcoords.com/components/tooltip.html#lc_tooltip
```ruby
lc_tooltip(text, id:, side: :top, **attributes, &block)
```
Tooltips: https://ui.lostcoords.com/components/tooltip.html
```erb
<%= lc_inline gap: :content do %>
<%= lc_tooltip "Copy a link to this page", id: "my-component-copy-tip" do |tip| %>
<%= lc_icon_button "Copy link", icon: "link", **tip %>
<% end %>
<%= lc_tooltip "Only owners can archive", id: "my-component-archive-tip", side: :bottom do |tip| %>
<%= lc_button "Archive", variant: :secondary, **tip %>
<% end %>
<% end %>
```
## lc_heading
https://ui.lostcoords.com/components/foundations.html#lc_heading
```ruby
lc_heading(content = nil, level: 2, size: :heading, trim: false, **attributes, &block)
```
Text styles: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_heading "Weekend in Kyoto", level: 2, size: :title %>
<%= lc_heading "Shared expenses", level: 3, size: :heading %>
<%= lc_heading "Dinner with friends", level: 4, size: :subheading %>
<%= lc_text do %>Use lc_stack to keep related content together.<% end %>
<%= lc_text "Add a receipt or a short note for your group.", size: :small, tone: :muted %>
<%= lc_text "Updated a few minutes ago", size: :caption, tone: :muted %>
```
Japanese text: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_heading "京都で過ごす週末、みんなの旅の記録", level: 3, size: :title %>
<%= lc_text "宿泊費や食事代をまとめて記録。誰がいくら支払ったか、グループのみんなで確認できます。" %>
<%= lc_text "レシートやメモを追加して、旅の思い出も一緒に残しましょう。", size: :small, tone: :muted %>
<%= lc_text "最終更新:数分前", size: :caption, tone: :muted %>
```
Eyebrow: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_text "Product", size: :eyebrow, tone: :muted %>
<%= lc_heading "Split costs with anyone", level: 3, size: :heading %>
<%= lc_text "プロダクト", size: :eyebrow, tone: :muted %>
<%= lc_heading "誰とでも費用を割り勘", level: 3, size: :heading %>
```
Page rhythm: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_stack gap: :section, class: "w-full max-w-xl" do %>
<%= lc_section title: "Recent expenses", actions: capture { lc_button("Add expense", icon: "plus", size: :sm) } do %>
<%= lc_card do %>
<%= lc_inline class: "flex-nowrap justify-between" do %>
<%= lc_text "Dinner with friends" %>
<%= lc_text "¥8,400", class: "shrink-0 tabular-nums" %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_text "Train tickets" %>
<% end %>
<% end %>
<%= lc_stack as: :section, gap: :heading do %>
<%= lc_section_header do %>
<%= lc_stack gap: :tight do %>
<%= lc_heading "Members" %>
<%= lc_text "Everyone who can see this workspace.", size: :small, tone: :muted %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_inline do %>
<%= lc_avatar "AK", class: "bg-primary" %>
<%= lc_stack gap: :tight do %>
<%= lc_text "Alex Kim" %>
<%= lc_text "Joined today", size: :small, tone: :muted %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
```
Responsive containers: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_container do %>
<%= lc_stack gap: :section do %>
<%= lc_heading "Plan your next trip", level: 2, size: :title %>
<%= lc_section title: "Travel details", level: 3 do %>
<%= lc_card do %>
<%= lc_stack do %>
<%= lc_text "Kyoto weekend", size: :body %>
<%= lc_text "Keep shared costs and travel notes together.", size: :small, tone: :muted %>
<%= lc_inline do %>
<%= lc_button "Invite friends", size: :sm %>
<%= lc_button "View itinerary", variant: :ghost, size: :sm %>
<% end %>
<% end %>
<% end %>
<% end %>
<%= lc_section title: "Shared costs", level: 3 do %>
<%= lc_card do %>
<%= lc_text "No expenses yet", size: :body %>
<% end %>
<% end %>
<% end %>
<% end %>
```
Popover sheet: https://ui.lostcoords.com/components/dialog.html
```erb
Filters
<%= lc_sheet id: "my-component-filters", popover: "auto", role: "dialog", aria: { labelledby: "my-component-filters-title" },
class: lc_glass_class(shape: :picker, extra: "sm:m-auto sm:w-80 sm:rounded-3xl text-foreground") do %>
<%= lc_heading "Filters", id: "my-component-filters-title", size: :title %>
A popover on desktop, a sheet you can swipe away on phones.
Done
<% end %>
```
Empty state: https://ui.lostcoords.com/components/empty_state.html
```erb
<%= lc_empty_state class: "w-full" do %>
<%= lc_icon_badge shape: :circle, tone: :primary, icon: "folder-plus", size: :lg%>
<%= lc_stack gap: :tight, class: "max-w-xs" do %>
<%= lc_heading "No projects yet", level: 3, size: :subheading %>
<%= lc_text "Create a project to get started.", size: :small, tone: :muted %>
<% end %>
<%= lc_button "Create project" %>
<% end %>
```
## lc_text
https://ui.lostcoords.com/components/foundations.html#lc_text
```ruby
lc_text(content = nil, size: :body, tone: :default, trim: false, as: :p, **attributes, &block)
```
Text styles: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_heading "Weekend in Kyoto", level: 2, size: :title %>
<%= lc_heading "Shared expenses", level: 3, size: :heading %>
<%= lc_heading "Dinner with friends", level: 4, size: :subheading %>
<%= lc_text do %>Use lc_stack to keep related content together.<% end %>
<%= lc_text "Add a receipt or a short note for your group.", size: :small, tone: :muted %>
<%= lc_text "Updated a few minutes ago", size: :caption, tone: :muted %>
```
Japanese text: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_heading "京都で過ごす週末、みんなの旅の記録", level: 3, size: :title %>
<%= lc_text "宿泊費や食事代をまとめて記録。誰がいくら支払ったか、グループのみんなで確認できます。" %>
<%= lc_text "レシートやメモを追加して、旅の思い出も一緒に残しましょう。", size: :small, tone: :muted %>
<%= lc_text "最終更新:数分前", size: :caption, tone: :muted %>
```
Eyebrow: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_text "Product", size: :eyebrow, tone: :muted %>
<%= lc_heading "Split costs with anyone", level: 3, size: :heading %>
<%= lc_text "プロダクト", size: :eyebrow, tone: :muted %>
<%= lc_heading "誰とでも費用を割り勘", level: 3, size: :heading %>
```
Page rhythm: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_stack gap: :section, class: "w-full max-w-xl" do %>
<%= lc_section title: "Recent expenses", actions: capture { lc_button("Add expense", icon: "plus", size: :sm) } do %>
<%= lc_card do %>
<%= lc_inline class: "flex-nowrap justify-between" do %>
<%= lc_text "Dinner with friends" %>
<%= lc_text "¥8,400", class: "shrink-0 tabular-nums" %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_text "Train tickets" %>
<% end %>
<% end %>
<%= lc_stack as: :section, gap: :heading do %>
<%= lc_section_header do %>
<%= lc_stack gap: :tight do %>
<%= lc_heading "Members" %>
<%= lc_text "Everyone who can see this workspace.", size: :small, tone: :muted %>
<% end %>
<% end %>
<%= lc_card do %>
<%= lc_inline do %>
<%= lc_avatar "AK", class: "bg-primary" %>
<%= lc_stack gap: :tight do %>
<%= lc_text "Alex Kim" %>
<%= lc_text "Joined today", size: :small, tone: :muted %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
```
Responsive containers: https://ui.lostcoords.com/components/foundations.html
```erb
<%= lc_container do %>
<%= lc_stack gap: :section do %>
<%= lc_heading "Plan your next trip", level: 2, size: :title %>
<%= lc_section title: "Travel details", level: 3 do %>
<%= lc_card do %>
<%= lc_stack do %>
<%= lc_text "Kyoto weekend", size: :body %>
<%= lc_text "Keep shared costs and travel notes together.", size: :small, tone: :muted %>
<%= lc_inline do %>
<%= lc_button "Invite friends", size: :sm %>
<%= lc_button "View itinerary", variant: :ghost, size: :sm %>
<% end %>
<% end %>
<% end %>
<% end %>
<%= lc_section title: "Shared costs", level: 3 do %>
<%= lc_card do %>
<%= lc_text "No expenses yet", size: :body %>
<% end %>
<% end %>
<% end %>
<% end %>
```
Default: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card class: "w-full" do |card| %>
<%= card.header title: "Project notes", description: "Keep related content together." do %>
<%= lc_button "Edit", variant: :secondary, size: :sm %>
<% end %>
<%= card.content do %>
<%= lc_text "Notes, links and files for the launch." %>
<% end %>
<%= card.footer do %>
<%= lc_button "Archive", variant: :ghost %>
<%= lc_button "Share" %>
<% end %>
<% end %>
```
Compact: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card padding: :sm, class: "w-full" do |card| %>
<%= card.header title: "Compact card", description: "Padding and gaps tighten together." %>
<%= lc_text "A compact summary.", size: :small %>
<% end %>
```
Edge-to-edge content: https://ui.lostcoords.com/components/card.html
```erb
<%= lc_card padding: :none, class: "w-full" do %>
<% [ [ "Design system", "Active" ], [ "Marketing site", "Draft" ] ].each do |name, status| %>
<%= lc_text name %>
<%= lc_text status, size: :small, tone: :muted %>
<% end %>
<% end %>
```
Copy from an element: https://ui.lostcoords.com/components/copy_button.html
```erb
<%= lc_stack gap: :related, class: "w-full max-w-md" do %>
<%= lc_field label: "Share link", id: "my-component-link" do |field| %>
<%= lc_input value: "https://ui.lostcoords.com", **field %>
<% end %>
<%= lc_copy_button "Copy current link", source: "my-component-link", copied_label: "Link copied", class: "w-full" %>
<%= lc_text "Edit the link, then copy it. The button reads the current value each time.", size: :small, tone: :muted %>
<% end %>
```
Empty state: https://ui.lostcoords.com/components/empty_state.html
```erb
<%= lc_empty_state class: "w-full" do %>
<%= lc_icon_badge shape: :circle, tone: :primary, icon: "folder-plus", size: :lg%>
<%= lc_stack gap: :tight, class: "max-w-xs" do %>
<%= lc_heading "No projects yet", level: 3, size: :subheading %>
<%= lc_text "Create a project to get started.", size: :small, tone: :muted %>
<% end %>
<%= lc_button "Create project" %>
<% end %>
```
Grouped controls: https://ui.lostcoords.com/components/field.html
```erb
<%= lc_stack class: "w-full max-w-sm" do %>
<%= lc_fieldset legend: "Split", id: "my-component-split", hint: "Everyone pays the same share unless you change it." do %>
<%= lc_inline do %>
<%= lc_toggle "Equally", active: true %>
<%= lc_toggle "By amount" %>
<%= lc_toggle "By share" %>
<% end %>
<% end %>
<%= lc_stack gap: :related do %>
<%= lc_text "This app can", size: :label, tone: :muted %>
Read your groups
Add expenses
<% end %>
<% end %>
```
Focus a field: https://ui.lostcoords.com/components/kbd.html
```erb
<%= lc_stack gap: :related, class: "w-full max-w-sm" do %>
<%= lc_field label: "Filter projects", id: "my-component-filter" do |field| %>
<%= lc_input name: "q", type: :search, placeholder: "Press / to filter", data: lc_shortcut_data("/"), **field %>
<% end %>
<%= lc_text size: :small, tone: :muted do %>
Press <%= lc_kbd "/" %> to filter, then <%= lc_kbd "escape" %> to clear.
<% end %>
<% end %>
```
Tones: https://ui.lostcoords.com/components/link.html
```erb
<%= lc_stack gap: :related do %>
<%= lc_text do %>Read the <%= lc_link "installation guide", "/installation.html" %> before you start.<% end %>
<%= lc_text size: :small, tone: :muted do %>Questions? <%= lc_link "Contact support", "/components/link.html", tone: :muted %>.<% end %>
<%= lc_text do %>See <%= lc_link "what's new", "/components/link.html", tone: :primary %> in this release.<% end %>
<% end %>
```
Cards: https://ui.lostcoords.com/components/radio.html
```erb
<%= lc_choice_group legend: "Plan", class: "w-full max-w-md" do %>
<%= lc_radio "Free", name: "my-component-plan", value: "free", hint: "Up to 3 projects.", card: true %>
<%= lc_radio "Team", name: "my-component-plan", value: "team", hint: "Shared projects and roles.", card: true, checked: true do %>
<%= lc_text "$12 per member, per month", size: :caption, tone: :muted %>
<% end %>
<%= lc_radio "Enterprise", name: "my-component-plan", value: "enterprise", hint: "SSO and audit logs.", card: true %>
<% end %>
```
Skip link: https://ui.lostcoords.com/components/skip_link.html
```erb
<%= lc_stack gap: :related, class: "items-center" do %>
<%= lc_text "Press Tab on this page: the skip link is the first thing to receive focus.", size: :small, tone: :muted %>
<%= lc_skip_link "#examples", class: "not-sr-only static" %>
<% end %>
```
Tabs: https://ui.lostcoords.com/components/tabs.html
```erb
<%= lc_tabs id: "my-component-tabs", label: "Project", class: "w-full" do |tabs| %>
<% tabs.panel "Overview" do %>
<%= lc_text "Pages, members and recent changes." %>
<% end %>
<% tabs.panel "Activity" do %>
<%= lc_text "Nothing new this week.", tone: :muted %>
<% end %>
<% tabs.panel "Settings" do %>
<%= lc_switch "Public project", name: "project[public]" %>
<% end %>
<% end %>
```
Vertical, with manual activation: https://ui.lostcoords.com/components/tabs.html
```erb
<%= lc_tabs id: "my-component-settings", label: "Settings", orientation: :vertical, activation: :manual, class: "w-full" do |tabs| %>
<% tabs.panel "Profile" do %>
<%= lc_text "Name, photo and contact details." %>
<% end %>
<% tabs.panel "Notifications" do %>
<%= lc_switch "Email me about mentions", name: "settings[mentions]" %>
<% end %>
<% tabs.panel "Billing" do %>
<%= lc_text "Plan, invoices and payment method.", tone: :muted %>
<% end %>
<% end %>
```
## lc_kbd
https://ui.lostcoords.com/components/kbd.html#lc_kbd
```ruby
lc_kbd(keys, **attributes)
```
Focus a field: https://ui.lostcoords.com/components/kbd.html
```erb
<%= lc_stack gap: :related, class: "w-full max-w-sm" do %>
<%= lc_field label: "Filter projects", id: "my-component-filter" do |field| %>
<%= lc_input name: "q", type: :search, placeholder: "Press / to filter", data: lc_shortcut_data("/"), **field %>
<% end %>
<%= lc_text size: :small, tone: :muted do %>
Press <%= lc_kbd "/" %> to filter, then <%= lc_kbd "escape" %> to clear.
<% end %>
<% end %>
```
## Blocks
Docs-only composition examples: https://ui.lostcoords.com/blocks.html
Copy and adapt the example files. Blocks are not importable library components.
### Application header
A glass header with navigation, an account menu and room for your brand.
https://ui.lostcoords.com/blocks/application_header.html
Replace the sample brand, links and account actions with your application's content.
Keep navigation destinations as links and account actions in the menu. The header's layout and scroll behavior live in the example files.
app/views/shared/_application_header.html.erb
```erb
<%# locals: (brand:, home: "/", home_label:, links: [], label: "Main", width: "max-w-5xl", navigation_class: "sm:flex") %>
<%# links: [[label, url, current], …]. The block's content renders the actions at the end of the bar. %>
```
app/assets/stylesheets/application_header.css
```css
.header-example__glass {
opacity: 0;
transition: opacity 300ms ease;
}
.header-example[data-scrolled] .header-example__glass {
opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
.header-example__glass {
transition: none;
}
}
```
app/javascript/controllers/blocks_header_controller.js
```javascript
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
connect() {
this.scroll()
}
// An open modal pins the body, so scrollY reads 0 until it closes; keep the
// state the page had rather than fading the glass out behind the dialog.
scroll() {
if (document.body.dataset.modalScrollLock === "true") return
this.element.toggleAttribute("data-scrolled", window.scrollY > 8)
}
}
```
### Documentation layout
A sidebar, page content and an "On this page" list, with a collapsible menu on phones.
https://ui.lostcoords.com/blocks/docs_shell.html
Render it as a layout: pass the sidebar and contents lists as locals and the page as the block. This documentation site uses it for every guide and component page.
Mark the current page with current: true so the sidebar sets aria-current. The contents list appears from the xl breakpoint.
app/views/shared/_docs_shell.html.erb
```erb
<%# locals: (navigation:, contents: nil, menu_label: "Menu", width: nil) %>
<%# navigation: the sidebar, usually lc_nav_list. contents: an optional "On this page" list for wide screens. %>
<%= menu_label %><%= lc_icon "chevron-down", options: { class: "size-4 transition-transform group-open/nav:rotate-180", "aria-hidden": true } %>
<%= navigation %>
<%= yield %>
<% if contents %>
<% end %>
```
app/assets/stylesheets/docs_shell.css
```css
/* The sidebar scrolls on its own without a visible scrollbar. */
.docs-shell__sidebar {
scrollbar-width: none;
}
.docs-shell__sidebar::-webkit-scrollbar {
display: none;
}
```
### Mobile navigation
A floating navigation pill and an expanding stack of quick actions.
https://ui.lostcoords.com/blocks/mobile_navigation.html
Choose a small set of primary destinations and replace the sample quick actions.
Copy the bottom spacing and safe-area rules with the controls, so page content remains reachable. Test keyboard visibility on a real phone.
app/views/shared/_mobile_navigation.html.erb
```erb
<%= lc_text "A space to make things", size: :caption, tone: :muted %>
Your little studio. A few good ideas, and room for a few more.
On your desk <%= lc_badge "This week" %>
<% [ [ "Brand refresh", "Finding a fresh perspective.", "swatch", :primary, "In progress" ], [ "Field notes", "Small observations, collected.", "book-open", :success, "Taking shape" ], [ "Summer collection", "Objects for everyday moments.", "sun", :neutral, "Just getting started" ] ].each do |title, description, icon, tone, status| %>
<%= lc_card class: "flex flex-col gap-content" do %>
<%= lc_icon_badge shape: :circle, icon: icon, size: :lg, tone: tone%><%= lc_badge status %>
<%= title %> <%= description %>
<%= lc_avatar "AL", size: :sm, class: "bg-background text-muted-foreground" %>You and your collaborators
<% end %>
<% end %>
Notes to self
<%= lc_card class: "flex flex-col gap-3" do %><%= lc_text "A thought for today", size: :caption, tone: :muted %>
Leave a little room. The best ideas sometimes arrive between the things you planned.
<% end %>
<%= lc_field label: "Capture a thought", id: "studio-thought", hint: "A small idea is a good place to start." do |field| %><%= lc_textarea name: "thought", placeholder: "What’s on your mind?", rows: 4, **field %><% end %>
Good company
<%= lc_card class: "flex flex-col gap-content" do %>
<% [ [ "AL", "Alex Lee", "Designer" ], [ "SK", "Sam Kim", "Writer" ], [ "JR", "Jamie Reed", "Maker" ] ].each do |initials, name, role| %>
<%= lc_avatar initials, class: "bg-background text-muted-foreground" %>
<%= lc_badge "Available", tone: :primary, class: "rounded-full text-sm" %>
<% end %>
<% end %>
<%= lc_icon "plus", options: { class: "size-7", "aria-hidden": true } %>
<%= lc_card class: "flex flex-col gap-3" do %><%= lc_badge "Draft" %>A fresh start. Make it your own.
<% end %>
```
app/assets/stylesheets/mobile_navigation.css
```css
.mobile-example {
--dock-gap: max(1rem, env(safe-area-inset-right, 0px));
--dock-bottom: max(0.75rem, env(safe-area-inset-bottom, 0px));
--dock-size: 4rem;
}
.mobile-example__main {
padding-block-end: calc(var(--dock-bottom) + var(--dock-size) + 2rem);
}
.mobile-example__tabs {
position: fixed;
z-index: var(--lc-z-sticky);
inset-inline: max(1rem, env(safe-area-inset-left, 0px)) calc(var(--dock-gap) + var(--dock-size) + 0.75rem);
bottom: var(--dock-bottom);
}
.mobile-example__tab {
position: relative;
display: flex;
min-width: 0;
min-height: 3.5rem;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 0.25rem;
border-radius: 999px;
color: var(--muted-foreground);
font-size: 0.6875rem;
font-weight: 600;
text-decoration: none;
}
.mobile-example__tab[aria-current="page"] {
color: var(--primary);
}
.mobile-example__indicator {
position: absolute;
z-index: -1;
inset-block: 0.25rem;
inset-inline-start: 0;
border-radius: 999px;
background: color-mix(in oklab, var(--foreground) 7%, transparent);
transition: translate 380ms var(--lc-ease-sheet, ease), width 380ms var(--lc-ease-sheet, ease);
}
.mobile-example__dock {
position: fixed;
z-index: calc(var(--lc-z-sticky) + 1);
inset-inline-end: var(--dock-gap);
bottom: var(--dock-bottom);
}
.mobile-example__trigger,
.mobile-example__action {
display: grid;
width: var(--dock-size);
height: var(--dock-size);
place-items: center;
padding: 0;
color: var(--primary);
cursor: pointer;
}
.mobile-example__trigger {
position: relative;
z-index: 2;
}
.mobile-example__trigger svg {
transition: rotate 300ms var(--lc-ease-sheet, ease);
}
.mobile-example__trigger[aria-expanded="true"] svg {
rotate: 135deg;
}
.mobile-example__actions {
visibility: hidden;
pointer-events: none;
}
.mobile-example__actions[data-open] {
visibility: visible;
}
.mobile-example__scrim {
position: fixed;
inset: 0;
border: 0;
background: color-mix(in oklab, var(--foreground) 18%, transparent);
opacity: 0;
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);
transition: opacity 220ms ease;
}
.mobile-example__actions[data-open] .mobile-example__scrim {
pointer-events: auto;
opacity: 1;
}
.mobile-example__action {
position: absolute;
z-index: 1;
inset: 0;
width: 3.5rem;
height: 3.5rem;
margin: 0.25rem;
color: var(--foreground);
opacity: 0;
transform: scale(0.4);
transition: transform 300ms ease, opacity 150ms ease;
}
.mobile-example__actions[data-open] .mobile-example__action {
pointer-events: auto;
opacity: 1;
transform: translateY(calc(var(--action-index) * -4.5rem)) scale(1);
transition: transform 420ms cubic-bezier(0.34, 1.45, 0.64, 1), opacity 160ms ease;
transition-delay: calc((var(--action-index) - 1) * 40ms);
}
.mobile-example__action-label {
position: absolute;
inset-inline-end: calc(100% + 0.75rem);
width: max-content;
max-width: calc(100vw - 7rem);
padding: 0.5rem 0.875rem;
border-radius: 999px;
background: var(--background);
box-shadow: var(--lc-shadow);
color: var(--foreground);
font-size: 0.875rem;
font-weight: 600;
}
.mobile-example[data-keyboard] .mobile-example__tabs,
.mobile-example[data-keyboard] .mobile-example__dock {
display: none;
}
@media (width >= 40rem) {
.mobile-example__tabs {
position: relative;
inset: auto;
width: max-content;
margin-inline: auto;
margin-block-end: 1.5rem;
}
.mobile-example__tab {
min-width: 7rem;
min-height: 2.75rem;
flex-direction: row;
gap: 0.5rem;
font-size: 0.875rem;
}
}
@media (prefers-reduced-motion: reduce) {
.mobile-example__indicator,
.mobile-example__trigger svg,
.mobile-example__scrim,
.mobile-example__action,
.mobile-example__actions[data-open] .mobile-example__action {
transition: none;
}
}
```
app/javascript/controllers/blocks_mobile_navigation_controller.js
```javascript
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["link", "panel", "indicator", "status", "projects", "notes", "draft"]
connect() {
this.resizeObserver = new ResizeObserver(() => this.placeIndicator())
this.linkTargets.forEach((link) => this.resizeObserver.observe(link))
this.onViewportResize = () => this.keyboard()
window.visualViewport?.addEventListener("resize", this.onViewportResize)
this.placeIndicator()
}
disconnect() {
this.resizeObserver.disconnect()
window.visualViewport?.removeEventListener("resize", this.onViewportResize)
}
select(event) {
event.preventDefault()
this.show(event.currentTarget.hash.slice(1))
}
home(event) {
event.preventDefault()
this.show("projects")
}
show(id) {
for (const link of this.linkTargets) {
if (link.hash === `#${id}`) link.setAttribute("aria-current", "page")
else link.removeAttribute("aria-current")
}
for (const panel of this.panelTargets) panel.hidden = panel.id !== id
this.placeIndicator()
}
placeIndicator() {
const active = this.linkTargets.find((link) => link.getAttribute("aria-current") === "page")
this.indicatorTarget.style.translate = `${active.offsetLeft}px 0`
this.indicatorTarget.style.width = `${active.offsetWidth}px`
}
add({ params: { destination } }) {
const draft = this.draftTarget.content.cloneNode(true)
const title = destination === "projects" ? "Untitled project" : "A new thought"
draft.querySelector("[data-draft-title]").textContent = title
const list = destination === "projects" ? this.projectsTarget : this.notesTarget
list.prepend(draft)
this.show(destination)
this.statusTarget.textContent = `${title} added. Your next idea starts here.`
}
keyboard() {
const typing = document.activeElement?.matches("input, textarea, [contenteditable=true]")
const inset = window.innerHeight - (window.visualViewport?.height ?? window.innerHeight)
this.element.toggleAttribute("data-keyboard", typing && inset > 150)
}
}
```
## Advanced styles
Class helpers style custom markup; the application owns its behavior.
Glass surfaces use lc_glass_class; lc_tw merges utility classes. Read https://github.com/lostcoords/ui#advanced-style-composition.
- `lc_icon_badge_class(size: :md, shape: :square, tone: :neutral, extra: nil)`
- `lc_avatar_class(size: :md, ink: false, linked: false, extra: nil)`
- `lc_avatar_stack_class(compact: false, extra: nil)`
- `lc_avatar_stack_row_class(extra: nil)`
- `lc_badge_class(tone: :neutral, shape: :rounded, extra: nil)`
- `lc_toggle_class(active: false, ghost: false, size: :md, extra: nil)`
- `lc_button_class(variant: :primary, tone: :default, size: :md, block: false, extra: nil)`
- `lc_select_trigger_class(size: :md, block: false, extra: nil)`
- `lc_icon_button_class(shape: :square, size: :md, variant: :ghost, tone: :default, extra: nil)`
- `lc_card_class(interactive: false, padding: :md, extra: nil)`
- `lc_choice_label_class(card: false, extra: nil)`
- `lc_checkbox_class(extra: nil)`
- `lc_radio_class(extra: nil)`
- `lc_switch_class(extra: nil)`
- `lc_dialog_class(kind = :modal, size: nil, extra: nil)`
- `lc_emoji_picker_groups`
- `lc_emoji_picker_count`
- `lc_emoji_picker_version`
- `lc_emoji_picker_search_text(emoji)`
- `lc_emoji_picker_search_name(emoji)`
- `lc_emoji_picker_search_labels(emoji)`
- `lc_emoji_picker_toneable?(emoji)`
- `lc_alert_class(extra: nil)`
- `lc_alert_icon(tone: :destructive)`
- `lc_spinner_class(size: :md, extra: nil)`
- `lc_skeleton_class(extra: nil)`
- `lc_empty_state_class(extra: nil)`
- `lc_toggle_group_class(extra: nil)`
- `lc_toggle_group_item_class(active: false, extra: nil)`
- `lc_input_class(size: :md, plain: false, extra: nil)`
- `lc_select_class(size: :md, extra: nil)`
- `lc_textarea_class(extra: nil)`
- `lc_field_class(size: :md, extra: nil)`
- `lc_field_label_class(size: :md, extra: nil)`
- `lc_glass_class(shape: :bar, thick: false, extra: nil)`
- `lc_stack_class(gap: :content, extra: nil)`
- `lc_inline_class(gap: :related, extra: nil)`
- `lc_container_class(size: :page, extra: nil)`
- `lc_section_header_class(extra: nil)`
- `lc_popover_class(align: :end, extra: nil)`
- `lc_menu_popover_class(align: :end, extra: nil)`
- `lc_menu_option_class(tone: :default, extra: nil)`
- `lc_link_class(tone: :inherit, extra: nil)`
- `lc_nav_link_class(compact: false, layout: :column, extra: nil)`
- `lc_prose_class(extra: nil)`
- `lc_table_class(extra: nil)`
- `lc_tw(*classes)`
- `lc_heading_class(size: :heading, trim: false, extra: nil)`
- `lc_text_class(size: :body, tone: :default, trim: false, extra: nil)`
- `lc_kbd_class(extra: nil)`
- `lc_shortcut_data(keys, data = {})`