Button
A button component that renders <button> elements with automatic form integration and auto-labeling.
Key Features
- Button Elements, Renders button tags for standalone buttons and form submissions
- Multiple Variants, Solid, outline, ghost, soft, and link styles
- Flexible Colors, Semantic colors (configurable) and standard UI colors
- Icon Support, Leading and trailing icons with color override
- Size Options, Six sizes from xs to xl
- Shape Variants, Rounded, pill, square, and circle shapes
- Form Integration, Auto-detects Rails form context with smart labeling
- States, Loading and disabled states with proper accessibility
- Turbo Loading Text, Automatic text swap during form submission via
loading_text - Full Width, Option to span container width
- Customizable, Additional HTML attributes and CSS classes
Basic Usage
The button component supports both positional and keyword argument styles:
<%= rui_button("Click Me", color: :primary) %>
<%= rui_button(text: "Click Me", color: :primary) %>
Standalone Button
Renders <button type="button"> automatically.
<%= rui_button("Click Me", color: :primary) %>
In Forms
Renders <button type="submit"> with auto-labeling.
<%= form_with(model: @post) do |f| %>
<%= f.rui_button %>
<% end %>
Variants
Five distinct visual styles.
<%= rui_button("Solid", variant: :solid) %>
<%= rui_button("Outline", variant: :outline) %>
<%= rui_button("Ghost", variant: :ghost) %>
<%= rui_button("Soft", variant: :soft) %>
<%= rui_button("Link", variant: :link) %>
Colors
Semantic Colors
<%= rui_button("Primary", color: :primary) %>
<%= rui_button("Success", color: :success) %>
<%= rui_button("Danger", color: :danger) %>
Tailwind Color Palette
Full Tailwind color support: slate, gray, zinc, blue, indigo, purple, pink, rose, red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, and more.
Sizes
<%= rui_button("Extra Small", size: :xs) %>
<%= rui_button("Small", size: :sm) %>
<%= rui_button("Base", size: :base) %>
<%= rui_button("Large", size: :lg) %>
<%= rui_button("Extra Large", size: :xl) %>
Shapes
<%= rui_button("Square", shape: :square) %>
<%= rui_button("Rounded", shape: :rounded) %>
<%= rui_button("Pill", shape: :pill) %>
States
Disabled
<%= rui_button("Disabled", disabled: true) %>
Loading
<%= rui_button("Loading...", loading: true) %>
Full Width
<%= rui_button("Full Width", full_width: true) %>
Turbo Loading Text
Use loading_text to show different text during form submission.
Turbo automatically swaps the button text and disables it while the request is in flight.
<%= form_with model: @post do |f| %>
<%= f.rui_button("Save", loading_text: "Saving...", color: :success) %>
<% end %>
<button data-turbo-submits-with="Saving...">Save</button>
How it works: The loading_text adds a data-turbo-submits-with
attribute. Turbo handles the UX automatically - swapping text and disabling the button during submission.
No JavaScript required!
Try it live
The Post form uses loading_text on its submit button. Fill out the form and click
"Create Post" to see the button text change to "Creating..." during submission.
With Icons
Add icons to buttons using the icon slot. Icons automatically inherit the button's color.
Requires: The lucide-rails gem must be installed. See Icon Component for details.
Leading Icons (Default)
Icons appear before the text by default:
<%= rui_button("Save", color: :success) do |button| %>
<% button.with_icon(name: :save) %>
<% end %>
Trailing Icons
Icons appear after the text when using position: :trailing:
<%= rui_button("Continue", color: :primary) do |button| %>
<% button.with_icon(name: :"arrow-right", position: :trailing) %>
<% end %>
Icon Sizes
Icons automatically scale with button size, or you can specify custom sizes:
<%= rui_button("Large", size: :lg, color: :success) do |button| %>
<% button.with_icon(name: :check, size: :lg) %>
<% end %>
Browse 1500+ available icons at lucide.dev/icons
Form Integration
The button component automatically detects form context and provides auto-labeling.
Auto-Labeling
Automatically generates "Create Model" or "Update Model" based on record state.
↑ For new records
↑ For existing records
<%= form_with(model: @post) do |f| %>
<%= f.rui_button %>
<% end %>
Custom Text
Override auto-labeling with custom text (positional argument).
<%= form_with(model: @post) do |f| %>
<%= f.rui_button("Save Changes", color: :success) %>
<%= f.rui_button("Save Draft", color: :secondary) %>
<% end %>
Multiple Submit Buttons
For Beginners
Sometimes you need different buttons in one form (like "Save Draft" vs "Publish").
Use name and value to know which button was clicked in your controller.
Basic Example: Save vs Publish
Click either button - they go to the same form action, but send different values.
<%= form_with model: @post do |f| %>
<%= f.text_field :title %>
<%= f.rui_button("Save Draft",
name: :commit,
value: "draft",
variant: :outline) %>
<%= f.rui_button("Publish",
name: :commit,
value: "publish",
color: :success) %>
<% end %>
In your controller:
def create
@post = Post.new(post_params)
case params[:commit]
when "publish"
@post.published = true
@post.published_at = Time.current
when "draft"
@post.published = false
end
if @post.save
redirect_to @post
else
render :new
end
end
Approve/Reject Pattern
Common for admin workflows, moderation, etc.
<%= f.rui_button("Approve",
name: :decision,
value: "approve",
color: :success) %>
<%= f.rui_button("Reject",
name: :decision,
value: "reject",
color: :danger) %>
Save and Continue Pattern
Multi-step forms, wizards, onboarding flows.
<%= f.rui_button("Save",
name: :action,
value: "save") %>
<%= f.rui_button("Save & Continue",
name: :action,
value: "save_continue",
color: :primary) %>
Advanced Form Features
For Senior Developers
HTML5 form attributes give you powerful control without JavaScript: skip validation, override actions, open in new tabs, and associate buttons with external forms.
Skip Validation (formnovalidate)
Perfect for "Save Draft" buttons - allows saving without meeting validation requirements. No JavaScript needed - native HTML5 feature!
<%= form_with model: @post do |f| %>
<%= f.text_field :title, required: true %>
<%= f.text_field :author, required: true %>
<%= f.rui_button("Save Draft",
formnovalidate: true,
variant: :outline) %>
<%= f.rui_button("Publish", color: :success) %>
<% end %>
Override Form Action (formaction)
Submit to different endpoints from the same form. Great for Preview, Export PDF, Send Email, etc.
<%= form_with model: @post do |f| %>
<%= f.text_field :title %>
<%= f.rui_button("Save") %>
<%= f.rui_button("Preview",
formaction: preview_post_path(@post),
variant: :outline) %>
<%= f.rui_button("Send Test Email",
formaction: email_preview_post_path(@post),
variant: :ghost) %>
<% end %>
Open in New Tab (formtarget)
Perfect for PDFs, print views, external processors - keeps your form page open.
<%= form_with model: @post do |f| %>
<%= f.rui_button("Generate PDF",
formaction: pdf_post_path(@post),
formtarget: "_blank") %>
<%= f.rui_button("Print Preview",
formaction: print_post_path(@post),
formtarget: "_blank",
variant: :outline) %>
<% end %>
External Form Association (form_id)
HTML5 lets you place buttons anywhere on the page - perfect for sticky headers, floating actions, split layouts.
<div class="sticky top-0 bg-white p-4">
<%= rui_button("Save Changes",
form_id: "post-form",
color: :success) %>
</div>
<%= form_with model: @post, id: "post-form" do |f| %>
<%= f.text_field :title %>
<%= f.text_area :content, rows: 20 %>
<% end %>
💡 Pro Tip
All these features are native HTML5 - no JavaScript, no Stimulus controllers, just browser standards. Combine them for powerful patterns: skip validation + open in new tab for "Preview Draft" workflows!
Block Content (Custom Layouts)
Use block syntax for icons, badges, multi-line text, or any custom HTML inside buttons.
Icon + Text
<%= rui_button(color: :success) do %>
<svg class="w-4 h-4 mr-2 inline-block">...</svg>
<span>Save Changes</span>
<% end %>
Badge + Text
<%= rui_button(variant: :ghost) do %>
<span>Messages</span>
<span class="ml-2 px-2 bg-red-500 text-white text-xs rounded-full">
3
</span>
<% end %>
Multi-line Button
<%= rui_button(size: :lg) do %>
<span class="block text-xs">Step 3 of 5</span>
<span class="block font-semibold text-lg">Complete</span>
<% end %>
Status Indicator
<%= rui_button(variant: :soft) do %>
<span class="w-2 h-2 bg-green-500 rounded-full mr-2 animate-pulse"></span>
<span>Live</span>
<% end %>
Note: When using block content, the text parameter is ignored.
The block content becomes the button's inner HTML.
See It In Action
Check out the Post CRUD example to see form integration with auto-labeling, validation, and multiple submit buttons.
View New Post FormAccessibility
The Button component follows WAI-ARIA best practices for accessible interactive elements.
ARIA Attributes
-
aria-disabled="true"when button is disabled (maintains focusability) -
aria-busy="true"during loading state -
aria-labelfor icon-only buttons without visible text -
Decorative icons hidden with
aria-hidden="true"
Keyboard Navigation
-
Tabto focus the button -
EnterorSpaceto activate -
Visible focus ring via
focus-visible:ring-2 - Disabled buttons remain focusable for discoverability
Semantic HTML
-
Native
<button>element with implicitrole="button" -
type="button"prevents accidental form submission -
type="submit"for form submission buttons -
Link buttons render as
<a>with properhref
Screen Reader Support
- Button text announced as accessible name
-
Loading state announced via
aria-busy -
Disabled state announced via
aria-disabled
API Reference
Appearance
Visual styling options
| Parameter | Type | Default | Description |
|---|---|---|---|
| variant | Symbol |
:solid
|
Visual style
:solid
:outline
:ghost
:soft
:link
|
| color | Symbol |
:primary
|
Color theme - semantic or any Tailwind color |
| size | Symbol |
:sm
|
Button size
:xs
:sm
:base
:md
:lg
:xl
|
| shape | Symbol |
:rounded
|
Border radius style
:square
:rounded
:pill
|
States
Button state options
| Parameter | Type | Default | Description |
|---|---|---|---|
| disabled | Boolean |
false
|
Disable button interaction |
| loading | Boolean |
false
|
Show loading state (sets aria-busy) |
| loading_text | String | — | Text shown during Turbo form submission (adds data-turbo-submits-with) |
| full_width | Boolean |
false
|
Make button full container width |
Form Context
Auto-passed when using f.rui_button
| Parameter | Type | Default | Description |
|---|---|---|---|
| form | FormBuilder | — | Form context (auto-passed by f.rui_button) |
| object | ActiveRecord | — | Model object for auto-labeling (Create/Update) |
Form Attributes
HTML5 form submission attributes for advanced multi-button forms
| Parameter | Type | Default | Description |
|---|---|---|---|
| name | String/Symbol | — | Button name attribute - sent in params when clicked |
| value | String | — | Button value - identifies which button was clicked |
| formmethod | Symbol | — |
Override form HTTP method
:get
:post
:patch
:put
:delete
|
| formaction | String | — | Override form action URL (preview, PDF, etc.) |
| formtarget | String | — | Where to open response: _blank, _self, _parent, _top |
| form_id | String | — | HTML5 form association - button can be outside form element |
| formnovalidate | Boolean |
false
|
Skip HTML5 validation when this button is clicked |
| formenctype | String | — | Override form encoding (multipart/form-data, etc.) |
Slots
Content slots for customizing component parts
| Slot | Description |
|---|---|
| icon | Icon via button.with_icon(:name) - inherits button color unless explicit color provided |