UikitRails
Beautiful, copy-paste UI components for Rails — inspired by shadcn/ui.
You don't install a component library. You copy components into your project and own the code. Customize everything — HTML, CSS, Ruby — no abstractions in the way.
Why UikitRails?
| Traditional gems | UikitRails | |
|---|---|---|
| Ownership | Locked behind gem API | Code lives in your app |
| Styling | Override with hacks | Edit the CSS directly |
| Tailwind required? | Often | No — plain CSS with design tokens |
| Customization | Limited to gem options | Change anything you want |
Features
- Copy, don't depend — components are copied into your app via generators. No runtime dependency.
- No Tailwind required — plain CSS powered by CSS custom properties (design tokens). Works with any CSS setup.
- ViewComponent-based — each component is a proper ViewComponent with a Ruby class and ERB template.
-
Dark mode ready — add
class="dark"to your<html>tag and it just works. - Built-in styleguide — mount the engine to browse live previews and copy code for every installed component.
- Accessible — semantic HTML, keyboard navigation, focus-visible states, and ARIA attributes.
Quick Start
1. Add the gem
gem "uikit_rails"bundle install2. Run the installer
rails generate uikit_rails:installThis creates two files:
| File | Purpose |
|---|---|
app/components/ui/base_component.rb |
Base class all UI components inherit from |
app/assets/stylesheets/uikit_rails.css |
Design tokens — colors, radii, fonts, transitions |
3. Add components
# Add specific components
rails generate uikit_rails:add button card input
# Or install everything at once
rails generate uikit_rails:add --allThis copies into your app:
| File | Purpose |
|---|---|
app/components/ui/button/component.rb |
ViewComponent Ruby class |
app/assets/stylesheets/ui/button.css |
Component styles (plain CSS) |
app/components/ui/button/preview.yml |
Preview examples for the styleguide |
Add multiple components at once:
rails generate uikit_rails:add button card badge alert4. Use in your views
<%= render Ui::Button::Component.new do %>
Click me
<% end %>
<%= render Ui::Button::Component.new(variant: :destructive, size: :lg) do %>
Delete
<% end %>
<%= render Ui::Button::Component.new(tag: :a, href: "/dashboard", variant: :outline) do %>
Go to Dashboard
<% end %>5. Use with Rails forms
Add the form component plus the field primitives it renders (same classes as standalone render Ui::…::Component):
rails generate uikit_rails:add input textarea select checkbox label button formThen use it in your views:
<%= form_with model: @user, builder: Ui::Form::Builder, class: "ui-form" do |f| %>
<%= f.field :name %>
<%= f.field :email, as: :email_field, placeholder: "you@example.com" %>
<%= f.field :bio, as: :text_area, rows: 4 %>
<%= f.field :role, as: :select, collection: %w[admin editor viewer] %>
<%= f.field :terms, as: :check_box, label: "I agree to the terms" %>
<%= f.submit "Save" %>
<% end %>Ui::Form::Builder lives at app/components/ui/form/builder.rb (not component.rb) so Zeitwerk can autoload the constant. Ui::Form::Builder uses ViewComponent (render_in) for f.email_field, f.text_area, etc., so markup matches <%= render Ui::Input::Component.new(...) %> outside forms.
The field helper auto-generates a label, the control, and error messages. You can also use individual helpers directly:
<%= form_with model: @user, builder: Ui::Form::Builder do |f| %>
<%= f.label :email %>
<%= f.email_field :email, placeholder: "you@example.com" %>
<%= f.submit "Save" %>
<% end %>To make it the app-wide default:
class ApplicationController < ActionController::Base
default_form_builder Ui::Form::Builder
endComponent Styleguide
UikitRails ships with a mountable engine that gives you a live component browser — like Storybook, but built into your Rails app.
Add one line to your routes:
# config/routes.rb
mount UikitRails::Engine => "/ui"Then visit /ui to see:
- A sidebar listing every installed component
- Live rendered previews with all variants and sizes
- Copyable ERB code snippets for every example
- The
rails generatecommand to install each component
The styleguide is self-contained — it has its own layout and styles that won't interfere with your app.
Available Components
Layout & Display
| Component | Description |
|---|---|
card |
Container with header, title, description, body, and footer slots |
separator |
Horizontal or vertical divider between content |
skeleton |
Animated placeholder for loading states |
avatar |
Circular avatar with image or fallback initials |
badge |
Small status indicator (default, secondary, destructive, outline) |
alert |
Informational banner with title and description (default, destructive) |
progress |
Progress bar with accessible ARIA attributes |
label |
Styled form label |
table |
Data table with header, body, footer, and caption slots |
Form Controls
| Component | Description |
|---|---|
button |
Button with 6 variants and 4 sizes, renders as <button> or <a>
|
form |
Form builder that renders the same ViewComponents as standalone usage (Ui::Input, etc.) |
input |
Styled text input field |
textarea |
Multi-line text input |
select |
Native select dropdown with custom styling |
checkbox |
Styled checkbox with optional label |
switch |
Toggle switch for boolean settings (pure CSS) |
toggle |
Pressable toggle button with pressed state |
Interactive (Stimulus)
| Component | Description |
|---|---|
dialog |
Modal dialog using native <dialog> element |
alert_dialog |
Confirmation dialog that requires user action |
sheet |
Slide-over panel from any side (top, right, bottom, left) |
dropdown |
Dropdown menu with items, separators, and labels |
popover |
Floating content panel triggered by click |
tabs |
Tabbed content panels with keyboard navigation |
tooltip |
Hover/focus tooltip (top, bottom, left, right) |
toast |
Dismissible notifications; position: sets fixed corner/center (six anchors), optional auto-dismiss (Stimulus) |
accordion |
Collapsible sections with single or multiple open |
collapsible |
Simple expand/collapse toggle |
Navigation
| Component | Description |
|---|---|
breadcrumb |
Navigation breadcrumb trail with links |
pagination |
Page navigation with prev, next, pages, and ellipsis |
Customization
Design Tokens
All components reference CSS custom properties defined in app/assets/stylesheets/uikit_rails.css. Change them once, every component updates:
:root {
--ui-primary: #2563eb;
--ui-primary-foreground: #ffffff;
--ui-radius: 0.5rem;
--ui-font-family: "Inter", sans-serif;
--ui-transition-speed: 150ms;
}Dark mode tokens are defined under .dark — add the class to <html> or <body> to switch.
Component Code
Since you own the code, you can change anything:
- Ruby class — add new variants, change defaults, add validations
- CSS file — restyle completely, add animations, adjust spacing
-
Preview — edit
preview.ymlto add your own examples to the styleguide
Example: Adding a Custom Variant
# app/components/ui/button/component.rb
VARIANTS = %i[default destructive outline secondary ghost link brand].freeze/* app/assets/stylesheets/ui/button.css */
.ui-btn--brand {
background-color: #7c3aed;
color: #ffffff;
}
.ui-btn--brand:hover {
background-color: #6d28d9;
}<%= render Ui::Button::Component.new(variant: :brand) do %>
Brand Button
<% end %>How It Works
rails generate uikit_rails:install
└─ copies base_component.rb + uikit_rails.css (design tokens)
rails generate uikit_rails:add button
└─ copies component.rb → app/components/ui/button/
└─ copies button.css → app/assets/stylesheets/ui/
└─ copies preview.yml → app/components/ui/button/
mount UikitRails::Engine => "/ui"
└─ serves a styleguide at /ui with live previews
The gem is only used for generators and the styleguide engine. Your components have zero runtime dependency on the gem — you could remove it from your Gemfile after adding all the components you need (though you'd lose the styleguide).
Requirements
- Ruby >= 3.2
- Rails >= 7.0
- view_component >= 3.0
Development
git clone https://github.com/kha-wogi/uikit_rails.git
cd uikit_rails
bin/setup
bundle exec rspec # run tests
bundle exec rubocop # run linterA test Rails app is included at test_app/ for manual testing:
cd test_app
bundle install
bin/rails generate uikit_rails:install
bin/rails generate uikit_rails:add button
bin/rails server
# Visit http://localhost:3000/uiContributing
Bug reports and pull requests are welcome on GitHub.
License
MIT