# RapidRailsUI > Production-ready ViewComponent UI library for Ruby on Rails with Tailwind CSS, Hotwire, and Stimulus JS. All helpers start with `rui_`. Designed for Rails 7+ without React or external JavaScript frameworks. ## About RapidRailsUI RapidRailsUI is a comprehensive component library that bridges the gap between Rails conventions and modern UI design. Built on ViewComponents, it provides 32 production-ready UI components that work seamlessly with Rails views, form builders, and Turbo/Hotwire. **Key Architecture**: - **ViewComponent-based**: Each component is an encapsulated, testable ViewComponent - **Tailwind CSS styling**: All styles defined via Tailwind utility classes in `styles.rb` - **Stimulus JS interactivity**: JavaScript behavior via Stimulus controllers (no plain JS) - **Form builder integration**: Use `f.rui_component` in form_with blocks - **Dark mode ready**: All components include dark mode variants automatically **Convention**: All helpers follow the `rui_` pattern for consistency. ## Key Conventions for AI Assistants When generating RapidRailsUI code, follow these critical patterns: ### Helper Method Naming All component helpers follow the pattern `rui_`: - `rui_button` - button component - `rui_link` - link component - `rui_checkbox` - checkbox component - etc. ### Argument Order Follows Rails Conventions RapidRailsUI follows standard Rails conventions for argument order: ```erb <%= rui_link("View Posts", posts_path) %> <%= rui_button("Click Me", color: :primary) %> <%= rui_button_to("Delete", post_path, method: :delete, color: :danger) %> <%= rui_link(posts_path, "View Posts") %> ``` ### Colors: Semantic + Tailwind Palette RapidRailsUI uses semantic colors AND Tailwind colors: ```erb <%= rui_button("Submit", color: :primary) %> <%= rui_badge(text: "Success", color: :success) %> <%= rui_alert(type: :danger) %> <%= rui_button("Action", color: :indigo) %> <%= rui_badge(text: "Tag", color: :amber) %> ``` Available semantic colors: `:primary`, `:secondary`, `:tertiary`, `:accent`, `:success`, `:danger`, `:warning`, `:info`, `:muted`, `:default` Available Tailwind colors: `:zinc`, `:gray`, `:red`, `:orange`, `:amber`, `:blue`, `:green`, `:indigo`, `:violet`, `:pink`, and many more. ### Form Builder Integration Use form builder methods within `form_with` blocks: ```erb <%= form_with(model: @post) do |f| %> <%= f.rui_input(:title, label: "Title") %> <%= f.rui_textarea(:body, label: "Body", rows: 8) %> <%= f.rui_checkbox(:published, label: "Publish this post") %> <%= f.rui_button %> <% end %> ``` ### Dark Mode All components automatically support dark mode via Tailwind's `dark:` variants. No manual dark mode styling needed. ```erb <%= rui_button("Click me") %> <%= rui_alert(type: :info) { "Dark-mode ready content" } %> ``` ## Component Reference All components are documented at https://rapidrails.cc/docs ### Form Controls - [Button](https://rapidrails.cc/docs/button) - `rui_button` - Form submissions and primary actions - [ButtonTo](https://rapidrails.cc/docs/button_to) - `rui_button_to` - RESTful action buttons (POST/PATCH/DELETE) - [Checkbox](https://rapidrails.cc/docs/checkbox) - `rui_checkbox` - Single or collection checkboxes with form builder support - [RadioButton](https://rapidrails.cc/docs/radio_button) - `rui_radio_button` - Radio button groups with multiple variants - [Input](https://rapidrails.cc/docs/input) - `rui_input` - Text input field with multiple types (text, email, password, number, tel, url, search) - [Textarea](https://rapidrails.cc/docs/textarea) - `rui_textarea` - Multi-line text input with auto-resize and character counter - [Select](https://rapidrails.cc/docs/select) - `rui_select` - Native HTML select. Works like Rails `f.select`: `f.rui_select(:status, ["Draft", "Published"])` or `f.rui_select(:author_id, Author.all, :id, :name)`. Also accepts keyword style: `f.rui_select(:field, collection: [...], label: "X")`. - [Combobox](https://rapidrails.cc/docs/combobox) - `rui_combobox` - Searchable dropdown with custom styling (Stimulus-powered) - [Date](https://rapidrails.cc/docs/date) - `rui_date` - Date/time input with multiple variants (input, picker, select) - [Upload](https://rapidrails.cc/docs/upload) - `rui_upload` - File upload with dropzone and multiple file support ### Navigation & Structure - [Link](https://rapidrails.cc/docs/link) - `rui_link` - Styled link with conditional rendering and Turbo support. **Note:** `email:`, `phone:`, `sms:`, `method: non-GET` params are deprecated — use dedicated helpers below. - [Mailto](https://rapidrails.cc/docs/link#mailto) - `rui_mailto(text, address)` - Email link with optional subject/body/cc - [Tel](https://rapidrails.cc/docs/link#tel) - `rui_tel(text, number)` - Phone link with optional country code - [SMS](https://rapidrails.cc/docs/link#sms) - `rui_sms(text, number)` - SMS link with optional pre-filled body - [Dropdown](https://rapidrails.cc/docs/dropdown) - `rui_dropdown` - Menu/dropdown for navigation or form selection - [Pagination](https://rapidrails.cc/docs/pagination) - `rui_pagination` - Built-in pagination with multiple variants (no external gems needed) - [Steps](https://rapidrails.cc/docs/steps) - `rui_steps` - Multi-step wizard with horizontal/vertical/minimal layouts ### Content Display - [Text](https://rapidrails.cc/docs/text) - `rui_text` - Typography with heading, paragraph, blockquote, and inline text - [TextFmt](https://rapidrails.cc/docs/text_fmt) - `rui_text_fmt` - Text with Rails formatting (truncate, numbers, time, linkify) - [Badge](https://rapidrails.cc/docs/badge) - `rui_badge` - Status badges with colors, sizes, shapes, and icons. **Note:** `status:` param is deprecated — use `color:` instead. - [Alert](https://rapidrails.cc/docs/alert) - `rui_alert` - Contextual feedback messages with variants and auto-dismiss. Supports `color:` override. **Cascade note:** `undo_url:` auto-enables `auto_dismiss:`, which auto-enables `animate:` and `show_progress_bar:` — pass these explicitly to avoid deprecation warnings. - [Table](https://rapidrails.cc/docs/table) - `rui_table` - Data table with sorting, selection, built-in pagination, and responsive modes - [CodeBlock](https://rapidrails.cc/docs/code_block) - `rui_code_block` - Syntax-highlighted code snippets with copy button ### Media & Visual - [Image](https://rapidrails.cc/docs/image) - `rui_image` - Semantic HTML image with captions, aspect ratios, and visual effects - [Avatar](https://rapidrails.cc/docs/avatar) - `rui_avatar` - User profile images, initials, or placeholders with status indicators - [Icon](https://rapidrails.cc/docs/icon) - `rui_icon` - 1500+ Lucide icons with color and size control (requires lucide-rails gem) - [SocialButton](https://rapidrails.cc/docs/social_button) - `rui_social_button` - Social platform/payment buttons with branded icons ### Interactive & Popovers - [Tooltip](https://rapidrails.cc/docs/tooltip) - `rui_tooltip` - Hover/focus tooltips with multiple position options - [Popover](https://rapidrails.cc/docs/popover) - `rui_popover` - Rich popovers with header, body, footer slots - [Dialog](https://rapidrails.cc/docs/dialog) - `rui_dialog` - Native HTML dialog element (modal or drawer) - [Accordion](https://rapidrails.cc/docs/accordion) - `rui_accordion` - Collapsible sections with single or multi-open support - [Kanban](https://rapidrails.cc/docs/kanban) - `rui_kanban` - Drag-and-drop kanban board with columns, cards, WIP limits, and server persistence ### Real-time & Search - [LiveSearch](https://rapidrails.cc/docs/live_search) - `rui_live_search` - Live search input with debounce and Turbo Frame updates - [Editable](https://rapidrails.cc/docs/editable) - `rui_editable` - Inline editable text with Turbo auto-save - [Clipboard](https://rapidrails.cc/docs/clipboard) - `rui_clipboard` - Copy-to-clipboard button with visual feedback ### Flash Messages - [FlashContainer](https://rapidrails.cc/docs/alert#flash-container) - `rui_flash_container` - Container for Turbo flash messages - [Flash Helper](https://rapidrails.cc/docs/alert#flash-helper) - `rui_flash` - Smart flash message rendering - [Errors Helper](https://rapidrails.cc/docs/alert#errors-helper) - `rui_errors` - Model validation error display - [AlertTurbo](https://rapidrails.cc/docs/alert#turbo-alert) - `rui_alert_turbo` - Single alert via Turbo Stream ## Component Selection for Code Generators When building apps from natural language descriptions, use existing RUI components instead of writing custom JavaScript. Every interactive component ships with its own Stimulus controller — **never write a custom Stimulus controller for behavior an RUI component already handles.** ### Composability Patterns — Component Nesting & Slots Many RUI components support **composition** via ViewComponent slots. Slots let you nest components inside each other for structured layouts. #### Dialog Composition (Modal Dialogs) Dialog uses 4 slots: `trigger`, `header`, `body`, `footer`. Always structure dialogs this way: ```erb <%= rui_dialog(title: "Confirm Action", size: :md) do |dialog| %> <% dialog.with_trigger { rui_button("Open Dialog", color: :primary) } %> <% dialog.with_header do %>

Are you sure you want to proceed?

<% end %> <% dialog.with_body do %>

This action cannot be undone. All data will be permanently deleted.

<% end %> <% dialog.with_footer do %> <%= rui_button("Cancel", variant: :outline, data: { action: "click->dialog#close" }) %> <%= rui_button_to("Confirm", action_path, method: :delete, color: :danger) %> <% end %> <% end %> ``` **Common mistakes:** - ❌ WRONG: Putting content directly in dialog block without slots → Content won't render - ❌ WRONG: Using `dialog.header` instead of `dialog.with_header` → Slot not recognized - ✅ RIGHT: Always use `with_*` slot methods for structured content #### Dropdown Composition (Action Menus) Dropdown has 13 slots (items, headers, dividers, search, footer, etc.). Most common pattern: ```erb <%= rui_dropdown do |dropdown| %> <% dropdown.with_trigger { rui_button("Actions", icon: :chevron_down) } %> <% dropdown.with_header(text: "User Actions") %> <% dropdown.with_item(text: "View Profile", href: profile_path, icon: :user) %> <% dropdown.with_item(text: "Edit Settings", href: settings_path, icon: :settings) %> <% dropdown.with_divider %> <% dropdown.with_item(text: "Sign Out", href: signout_path, icon: :log_out, color: :danger) %> <% end %> ``` **Common mistakes:** - ❌ WRONG: Using `rui_dropdown` inside `form_with` for field selection → Use `rui_select` instead - ❌ WRONG: Manually building dropdown HTML → Use slot methods - ✅ RIGHT: Use `with_item` for each menu option, `with_divider` for separators #### Table Composition (Data Tables) Table uses nested slots: `with_column` + `with_row` → `row.with_cell`. Imperative loop required: ```erb <%= rui_table(striped: true, hoverable: true) do |table| %> <% table.with_column(key: :name, label: "Name", sortable: true) %> <% table.with_column(key: :email, label: "Email") %> <% table.with_column(key: :role, label: "Role") %> <% table.with_column(key: :actions, label: "Actions", align: :right) %> <% @users.each do |user| %> <% table.with_row(id: user.id) do |row| %> <% row.with_cell { user.name } %> <% row.with_cell { user.email } %> <% row.with_cell { rui_badge(text: user.role, color: :primary) } %> <% row.with_cell do %> <%= rui_link("Edit", edit_user_path(user), icon: :edit) %> <%= rui_button_to("Delete", user_path(user), method: :delete, color: :danger, size: :sm) %> <% end %> <% end %> <% end %> <% end %> ``` **Critical pattern:** Column-cell binding is **POSITIONAL** — column 1 maps to cell 1 by order. If you add/remove columns, add/remove cells in same order. **Common mistakes:** - ❌ WRONG: Column count doesn't match cell count → Data under wrong headers - ❌ WRONG: Forgetting `@users.each` loop → No rows render - ❌ WRONG: Using `rui_table(@users)` without block → No columns defined - ✅ RIGHT: Define columns, loop records, match cell count to column count #### Accordion Composition (Collapsible Sections) Accordion uses `with_item` slot for each panel: ```erb <%= rui_accordion(exclusive: true) do |accordion| %> <% accordion.with_item(title: "What is RapidRailsUI?") do %>

A production-ready ViewComponent UI library for Rails with 32 components.

<% end %> <% accordion.with_item(title: "How do I install it?") do %>

Add to Gemfile: gem 'rapid_rails_ui'. Run bundle install.

<% end %> <% accordion.with_item(title: "What about dark mode?", open: true) do %>

All components automatically support dark mode via Tailwind's dark: variants.

<% end %> <% end %> ``` **Common mistakes:** - ❌ WRONG: Using `accordion.item` instead of `accordion.with_item` → Slot not recognized - ✅ RIGHT: Use `with_item(title:)` for each collapsible section #### Kanban Composition (Drag-and-Drop Board) Kanban uses nested slots: `board.with_column` → `col.with_card`. Cards accept any block content. ```erb <%= rui_kanban(move_url: kanban_move_path) do |board| %> <% board.with_column(title: "To Do", id: "todo", color: :zinc) do |col| %> <% col.with_card(id: "card-1", color: :danger) do %>
<%= rui_badge(text: "Bug", color: :danger, size: :sm) %>

Fix login bug

<% end %> <% col.with_footer do %> <% end %> <% end %> <% board.with_column(title: "In Progress", id: "wip", max_cards: 3, badge_count: 2) do |col| %> <% col.with_card(id: "card-2") do %>

Design dashboard

<% end %> <% end %> <% end %> ``` **Common mistakes:** - ❌ WRONG: Missing `id:` on columns or cards → Drag-and-drop breaks - ❌ WRONG: Writing custom drag-and-drop JS → Use `rui_kanban` with `move_url:` for auto-PATCH - ✅ RIGHT: Use `board.with_column(id:, title:)` for columns, `col.with_card(id:)` for cards #### Icon Slots (Buttons, Links, Badges) Many components accept icon slots for visual enhancement: ```erb <%= rui_button("Save Changes", color: :primary) do |button| %> <% button.with_icon(:save) %> <% end %> <%= rui_button("Save", icon: :save, color: :primary) %> <%= rui_link("Documentation", docs_path) do |link| %> <% link.with_icon(:book_open) %> <% end %> <%= rui_badge(text: "Active") do |badge| %> <% badge.with_icon(:check_circle) %> <% end %> ``` **Common mistakes:** - ❌ WRONG: Using string `"heart"` instead of symbol `:heart` → Icon not found - ❌ WRONG: Mixing `icon:` param AND `with_icon` slot → Slot overrides param - ✅ RIGHT: Use symbol for icon name, choose either param OR slot (not both) ### Disambiguation — Ambiguous Terms These terms commonly cause wrong component selection. Match carefully: **"Search":** - "Search/filter a table" / "filter rows" → `rui_input` with `type: :search` placed above a `rui_table`. The table has NO built-in search — use a separate input. **NOT** `rui_live_search`. - "Global search" / "Cmd+K" / "search popup" / "search the whole app" → `rui_live_search` (standalone search with optional modal, debounced queries via Turbo Frame — needs a search controller endpoint). - "Searchable dropdown" / "type to filter options" → `rui_combobox` (form field with type-to-filter). **"Dropdown":** - "Actions menu" / "context menu" / "navigation dropdown" → `rui_dropdown` (clickable menu with items). - "Form select field" / "pick one option" → `rui_select` (native HTML select) or `rui_combobox` (searchable). **"Editable":** - "Click to edit" / "inline edit" / "edit in place" → `rui_editable` (click text → input appears → auto-save via PATCH on blur/Enter, cancel on Escape). Needs controller `respond_to` with `format.turbo_stream { head :ok }`. - "Edit form" / "form page" → Standard `form_with` with `f.rui_input`, `f.rui_textarea`, etc. **"Modal" / "Popup":** - "Confirmation dialog" / "modal form" / "drawer panel" → `rui_dialog` (native HTML dialog element). - "Small hover hint" → `rui_tooltip` (text-only, hover/focus triggered). - "Rich info card on click" → `rui_popover` (header/body/footer, click triggered). **"Table":** - "Data table" / "sortable list" / "table with selection" → `rui_table` (sorting, row selection, bulk actions, pagination via `pagy:`). No built-in search — pair with `rui_input(type: :search)` for filtering. - "Card grid" / "simple list" → Manual HTML layout with RUI components inside. **"Button":** - "Submit form" / "primary action" → `rui_button` (inside a form, or standalone). - "Delete" / "POST/PATCH/DELETE action" → `rui_button_to` (RESTful action, generates its own form). - "Navigation that looks like a button" → `rui_link` with button-like styling. ### Interactive Components with Bundled Stimulus Controllers These components include JavaScript behavior — never rewrite this logic: | Component | Controller | What It Does | |---|---|---| | `rui_editable` | `editable` | Click-to-edit, auto-save PATCH, Enter/Escape/blur | | `rui_live_search` | `live-search` | Debounced search, Turbo Frame results, optional Cmd+K modal | | `rui_dialog` | `dialog` | Modal/drawer open/close, backdrop click, Escape | | `rui_accordion` | `accordion` | Expand/collapse, single or multi-open | | `rui_table` | `table` | Row selection, bulk actions, sortable columns | | `rui_combobox` | `combobox` | Searchable dropdown, keyboard nav | | `rui_clipboard` | `clipboard` | Copy-to-clipboard with feedback | | `rui_upload` | `upload` | Drag-and-drop, file preview, progress | | `rui_steps` | `steps` | Multi-step wizard navigation | | `rui_checkbox` | `checkbox` | Indeterminate state, group select-all | | `rui_date` | `date-picker` | Calendar popup, date range, time | | `rui_kanban` | `kanban` | Drag-and-drop columns/cards, keyboard nav, auto-PATCH | ### Controller Setup for Interactive Components Some components send requests to the server. Your Rails controller must handle them: ```erb <%# rui_editable sends a PATCH via fetch — controller must respond: %> format.turbo_stream { head :ok } # success format.json { render json: { errors: @model.errors.full_messages }, status: :unprocessable_entity } # failure ``` ### Common Mistakes — Wrong/Right Examples These are the most frequent mistakes when generating RUI code: #### Mistake 1: Using rui_dropdown for form field selection ```erb <%= form_with model: @post do |f| %> <%= f.rui_dropdown(:category_id, Category.all, :id, :name) %> <% end %> <%= form_with model: @post do |f| %> <%= f.rui_select(:category_id, Category.all, :id, :name) %> <% end %> ``` **Why:** `rui_dropdown` is a navigation/action menu component. Use `rui_select` (native HTML select) or `rui_combobox` (searchable) for form fields. #### Mistake 2: Using rui_live_search to filter table rows ```erb <%= rui_live_search(url: filter_posts_path, turbo_frame: "posts") %> <%= rui_table(@posts) do |table| %> <%# ... %> <% end %> <%= rui_input(type: :search, placeholder: "Filter posts...", data: { action: "keyup->filter#search" }) %> <%= rui_table(@posts, data: { filter_target: "table" }) do |table| %> <%# ... %> <% end %> ``` **Why:** `rui_live_search` sends debounced queries to the server (for global app search). Table filtering is typically client-side using a simple input. #### Mistake 3: Using rui_button for delete actions ```erb <%= rui_button("Delete", data: { turbo_method: :delete, turbo_confirm: "Sure?" }) %> <%= rui_button_to("Delete", post_path(@post), method: :delete, data: { turbo_confirm: "Sure?" }, color: :danger) %> ``` **Why:** `rui_button_to` generates a proper form with CSRF token and HTTP method override. Plain `rui_button` is for in-form submissions or JavaScript actions. #### Mistake 4: Wrong parameter names (deprecated/renamed) ```erb <%= rui_text(tag: :h1) { "Title" } %> <%= rui_badge(text: "Active", status: :success) %> <%= rui_text(as: :h1) { "Title" } %> <%= rui_badge(text: "Active", color: :success) %> <%= rui_text("Hello", line_height: :tight, letter_spacing: :wide) %> ``` **Why:** `rui_text` uses `as:` not `tag:`. `rui_badge` deprecated `status:` in favor of `color:`. Use `line_height:` and `letter_spacing:` for text spacing control. #### Mistake 5: Mismatched column/cell count in tables ```erb <%= rui_table(striped: true) do |table| %> <% table.with_column(key: :name, label: "Name") %> <% table.with_column(key: :email, label: "Email") %> <% table.with_column(key: :role, label: "Role") %> <% @users.each do |user| %> <% table.with_row do |row| %> <% row.with_cell { user.name } %> <% row.with_cell { user.email } %> <% end %> <% end %> <% end %> <%= rui_table(striped: true) do |table| %> <% table.with_column(key: :name, label: "Name") %> <% table.with_column(key: :email, label: "Email") %> <% table.with_column(key: :role, label: "Role") %> <% @users.each do |user| %> <% table.with_row do |row| %> <% row.with_cell { user.name } %> <% row.with_cell { user.email } %> <% row.with_cell { rui_badge(text: user.role, color: :primary) } %> <% end %> <% end %> <% end %> ``` **Why:** Table column-cell binding is **positional**. Column 1 maps to cell 1, column 2 to cell 2, etc. Mismatch causes data under wrong headers. #### Mistake 6: Using string instead of symbol for icons ```erb <%= rui_button("Save", icon: "heart", color: :primary) %> <%= rui_button("Save", icon: :heart, color: :primary) %> ``` **Why:** Lucide icon lookup requires symbol keys. String keys won't find icons. #### Mistake 7: Putting content directly in component blocks without slots ```erb <%= rui_dialog(title: "Confirm") do %>

Are you sure?

<%= rui_button("OK") %> <% end %> <%= rui_dialog(title: "Confirm") do |dialog| %> <% dialog.with_body do %>

Are you sure?

<% end %> <% dialog.with_footer do %> <%= rui_button("OK", color: :primary) %> <% end %> <% end %> ``` **Why:** Components with slots (Dialog, Dropdown, Accordion) require explicit slot methods. Direct content in the block is ignored. #### Mistake 8: Expecting size: to work with heading tags ```erb <%# WRONG: size: is ignored when as: is h1-h6 %> <%= rui_text("Title", as: :h1, size: :xl) %> <%# Renders text-5xl md:text-6xl (h1 preset), NOT text-xl %> <%# RIGHT: Headings have built-in responsive sizes %> <%= rui_text("Title", as: :h1) %> <%# RIGHT: For custom-sized heading-like text, skip as: %> <%= rui_text("Small Title", size: :lg, weight: :bold) %> ``` **Why:** When `as:` is h1-h6, `size:` is completely ignored — headings use TypographyHelper responsive presets. Explicit `weight:` DOES override the heading default. #### Mistake 9: Deprecated dialog backdrop param ```erb <%# WRONG: dismissible: is deprecated %> <%= rui_dialog(title: "Confirm", dismissible: false) do |d| %> Content <% end %> <%# RIGHT: Use backdrop_close: %> <%= rui_dialog(title: "Confirm", backdrop_close: false) do |d| %> Content <% end %> ``` **Why:** `dismissible:` was renamed to `backdrop_close:` to distinguish it from `closable:` (the X button). Using the old name emits a deprecation warning. #### Mistake 10: Deprecated upload file size param ```erb <%# WRONG: max_file_size: is deprecated %> <%= rui_upload(:avatar, max_file_size: 2.megabytes) %> <%# RIGHT: Use max_file_size_bytes: %> <%= rui_upload(:avatar, max_file_size_bytes: 2.megabytes) %> ``` **Why:** Renamed to make the unit explicit (bytes). ## Common Usage Patterns ### Simple Button ```erb <%= rui_button("Click Me") %> <%= rui_button("Submit", color: :primary, size: :lg) %> <%= rui_button("Delete", color: :danger, variant: :outline) %> ``` ### Form with Inputs ```erb <%= form_with(model: @post) do |f| %> <%= f.rui_input(:title, label: "Title") %> <%= f.rui_textarea(:body, label: "Body", rows: 8, auto_resize: true) %> <%= f.rui_checkbox(:published, label: "Publish") %> <%= f.rui_button %> <% end %> ``` ### Navigation ```erb
<%= rui_link("Home", root_path, unless_current: true) %> <%= rui_link("Posts", posts_path, unless_current: true) %> <%= rui_link("Settings", settings_path, unless_current: true) %>
``` ### Social Media Links with Icons ```erb
<%= rui_link(url: "https://twitter.com/username", color: :primary, external: true, title: "Twitter") do |link| %> <% link.with_icon(:twitter) %> <% end %> <%= rui_link(url: "https://github.com/username", color: :primary, external: true, title: "GitHub") do |link| %> <% link.with_icon(:github) %> <% end %> <%= rui_link(url: "https://linkedin.com/company/yourcompany", color: :primary, external: true, title: "LinkedIn") do |link| %> <% link.with_icon(:linkedin) %> <% end %>
``` **Key points for social media links:** - Use `url:` as keyword argument (not positional) when using block syntax - `external: true` adds security attributes (`rel="noopener noreferrer"` and `target="_blank"`) - `title:` attribute improves accessibility for icon-only links - Block syntax with `link.with_icon()` required for icons - Icons inherit link color unless custom `color:` specified on icon ### Table with Selection ```erb <%= rui_table(selectable: true, sortable: true) do |table| %> <% table.with_column(key: :name, label: "Name", sortable: true) %> <% table.with_column(key: :email, label: "Email") %> <% table.with_bulk_actions do %> <%= rui_bulk_action("Delete", url: bulk_destroy_path, method: :delete, color: :danger) %> <% end %> <% @users.each do |user| %> <% table.with_row(id: user.id) do |row| %> <% row.with_cell { user.name } %> <% row.with_cell { user.email } %> <% end %> <% end %> <% end %> ``` ### Alert from Flash ```erb
<%= rui_flash %>
``` Then in your controller: ```ruby redirect_to posts_path, notice: "Post created successfully" ``` ### Inline Editable Field ```erb <%= rui_editable @post, :title, url: post_path(@post), as: :h1, class: "text-2xl font-bold" %> ``` ### Multi-step Wizard ```erb <%= rui_steps(id: "registration", url: registration_path, current_step: @step) do |steps| %> <% steps.with_step(title: "Account Info") do %> <%= render "account_form" %> <% end %> <% steps.with_step(title: "Profile") do %> <%= render "profile_form" %> <% end %> <% steps.with_step(title: "Confirm") do %> <%= render "confirmation" %> <% end %> <% end %> ``` ## Built-in Pagination (No External Gems Needed) RapidRailsUI includes its own pagination service. No need to install Pagy, Kaminari, or any other pagination gem. The `rui_paginate` helper is automatically available in all your controllers with zero configuration. ```ruby # In your controller — nothing to install, include, or configure: class PostsController < ApplicationController def index @pagy, @posts = rui_paginate(Post.all, limit: 10) end end ``` ```erb <%# In your view: %> <%= rui_pagination(pagy: @pagy) %> <%# Or with table (shows "Showing X-Y of Z" in footer): %> <%= rui_table(pagy: @pagy) do |table| ... end %> ``` **Features:** - Works with ActiveRecord relations and plain Arrays - Handles edge cases: page clamping, empty collections, grouped queries - Accepts `limit:` (items per page) and `page_param:` (query param name, defaults to `:page`) ## Critical Constraints & Gotchas 1. **Argument order follows Rails**: `rui_link(text, url)` just like Rails `link_to(text, url)` - text first 2. **Use `rui_button_to` for destructive actions**: Not `rui_link` with method: option 3. **Icons require lucide-rails**: Install the gem to use `rui_icon` 4. **Form methods are on the form builder**: Use `f.rui_checkbox` in forms, not standalone 5. **Dark mode is automatic**: Don't add manual `dark:` classes to components 6. **Symbols not strings for options**: Use `color: :primary` not `color: "primary"` 7. **Form builder auto-labels buttons**: `f.rui_button` generates "Create Post" or "Update Post" automatically 8. **Turbo integration for real-time**: Components like LiveSearch, Editable, Dialog work best with Turbo Frames ## Component Output Reference | Component | Tag | Display | Key Behavior | |---|---|---|---| | `rui_text` | `

` default | block (span=inline) | `

` adds mb-2; h1-h6 ignore size: | | `rui_text_fmt` | `

` default | block (span=inline) | Same as rui_text + formatting (truncate, highlight, currency, time_ago) | | `rui_avatar` | ``/`` | inline | name: auto-generates initials | | `rui_badge` | ``/`` | inline | Safe inside text/table cells | | `rui_button` | `