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.

Open New Post Form

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!

← Skips validation (will submit empty form)
← Requires validation (won't submit if empty)
<%= 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.

→ Goes to /posts
→ Goes to #preview
→ Goes to #email
<%= 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.

← Opens in new tab
← Opens in new tab
<%= 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.

Edit Post

↑ Notice no submit button here - it's in the sticky header!


<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 Form

Accessibility

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-label for icon-only buttons without visible text
  • Decorative icons hidden with aria-hidden="true"

Keyboard Navigation

  • Tab to focus the button
  • Enter or Space to activate
  • Visible focus ring via focus-visible:ring-2
  • Disabled buttons remain focusable for discoverability

Semantic HTML

  • Native <button> element with implicit role="button"
  • type="button" prevents accidental form submission
  • type="submit" for form submission buttons
  • Link buttons render as <a> with proper href

Screen Reader Support

  • Button text announced as accessible name
  • Loading state announced via aria-busy
  • Disabled state announced via aria-disabled

API Reference

rui_button

Button element with automatic form integration and auto-labeling

Parameter Type Default Description
text String Button label text - supports positional or keyword argument. Auto-generated in forms if not provided.

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

Related Components