ViewPrimitives

A shadcn/ui-inspired component library for Rails built on ViewComponent.

Acknowledgements — The visual design, CSS class choices, and component structure of ViewPrimitives are heavily inspired by shadcn/ui and its Svelte port shadcn-svelte. We are grateful to @shadcn and all contributors for their outstanding open-source work. ViewPrimitives is an independent Rails adaptation and is not affiliated with or endorsed by the shadcn/ui project.

Components are copied into your app via a generator — not imported from a package. Tailwind classes live in your own files, so any Tailwind setup works out of the box: tailwindcss-rails, cssbundling-rails, Vite, esbuild — no configuration required.

Requirements

  • Ruby >= 3.2 (developed with 4.0.5 — use mise or see .ruby-version)
  • Rails >= 7.1 (required by ViewComponent 4)
  • ViewComponent >= 4.0
  • Tailwind CSS (any setup)

Installation

Add to your Gemfile:

gem "view_primitives"

Then run the install generator:

rails g view_primitives:install

This will:

  • Create app/components/application_component.rb with ViewPrimitives::ClassHelper included (skipped if you already have one — add include ViewPrimitives::ClassHelper manually)
  • Create app/assets/stylesheets/view_primitives.css with the design token definitions (@theme inline + oklch light/dark theme)

Then import it in your Tailwind CSS entry point:

/* tailwindcss-rails  → app/assets/tailwind/application.css              */
/* tailwind (legacy)  → app/assets/stylesheets/application.tailwind.css  */
/* cssbundling/Vite   → app/javascript/application.css                    */

@import "./view_primitives";

The install generator auto-detects these entry points and injects the import when possible.

UI namespace

Components live under UI:: (files in app/components/ui/). The gem registers the UI acronym with ActiveSupport so ui :button resolves to UI::ButtonComponent.

That's it — no tailwind.config.js required. Tailwind 4 reads the @theme inline block directly from the CSS.

Adding components

rails g view_primitives:list                         # available + installed status
rails g view_primitives:add button
rails g view_primitives:add button alert accordion   # multiple at once

Each component is copied into app/components/ui/ as plain Ruby and ERB files you own and can modify freely. Re-running add overwrites existing files (a warning is printed). Unknown component names fail with a non-zero exit code.

View helpers

ViewPrimitives adds the ui helper to views and mailers:

<%# Positional label — no block needed %>
<%= ui :button, "Save changes", variant: :outline %>
<%= ui :alert, title: "Heads up!", description: "Check your settings." %>
<%= ui :accordion, items: [{ title: "FAQ", content: "Answer here." }] %>

<%# Block — for icons, slots, or complex content %>
<%= ui :button do %><svg .../> Save<% end %>
<%= ui :alert do |a| %><% a.with_alert_title { "Note" } %><% end %>

ui is shorthand for render UI::SomeComponent.new(...). For components outside app/components/ui/, use render as usual.

Components

Available now

Component Description Docs
Button Clickable element with 6 variants and 4 sizes docs
Alert Informational banner with title and description slots docs
Accordion Collapsible sections via native <details>, optional exclusive mode docs
Badge Small status label with variants docs
Avatar User avatar with image and initials fallback docs
Card Container with header, content, and footer slots docs
Separator Horizontal or vertical divider docs
Label Accessible form label docs
Skeleton Loading placeholder with pulse animation docs
Progress Progress bar with value prop docs
Aspect Ratio Constrains child content to a given aspect ratio docs
Spinner Animated loading indicator docs
KBD Keyboard shortcut key display docs
Rating Read-only star rating display docs
Rating Input Interactive star rating — form or AJAX submission docs
Indicator Status dot or count badge overlaid on an element docs
List Group Bordered list with optional links and active state docs
Banner Styled announcement strip with variants docs
Button Group Visually joined row of buttons docs
Input Styled text input with ring/border docs
Textarea Styled multi-line input docs
Checkbox Accessible checkbox with optional label docs
Radio Group Group of radio inputs docs
Select Native styled select element docs
Switch CSS-only on/off toggle docs
Toggle Single pressable toggle button docs
Toggle Group Group of related toggles (single or multiple) docs
Form Field Label + input + hint + error layout wrapper docs
File Input Styled file upload input docs
Search Input Text input with built-in search icon and clear button docs
Number Input Text input with increment/decrement controls docs
Range Styled range slider docs
Floating Label Input with floating placeholder label docs
Breadcrumb Navigational breadcrumb trail with separator docs
Pagination Page number links with prev/next and ellipsis docs
Stepper Multi-step progress indicator (horizontal + vertical) docs
Tabs Tab bar with content panels (array API + slot API) docs
Navbar Responsive top navigation bar with hamburger menu docs
Navigation Menu Top-level navigation with optional dropdown flyouts docs
Bottom Nav Mobile-style tab bar fixed to the bottom docs
Footer Page footer with columns, links, and copyright docs
Mega Menu Full-width dropdown panel with grouped links and images docs
Dialog Modal dialog with trigger, title, description, footer slots docs
Alert Dialog Blocking confirmation dialog docs
Sheet Slide-in panel from any edge (left/right/top/bottom) docs
Drawer Bottom sheet with drag handle — mobile drawer pattern docs
Popover Floating panel anchored to a trigger docs
Tooltip Hover label — CSS-only, no JS docs
Hover Card Rich hover preview card — CSS-only, no JS docs
Dropdown Menu Trigger-anchored menu with items and separators docs
Context Menu Right-click context menu positioned at cursor docs
Menubar Horizontal application-style menu bar docs
Command Modal command palette with live search filtering docs
Combobox Autocomplete select with live search docs
Calendar Date picker calendar grid docs
Date Picker Input that opens a Calendar popover docs
Timepicker Input for selecting a time value docs
Carousel Scrollable item carousel with prev/next controls docs
Data Table Sortable, filterable table with pagination docs
Sidebar Collapsible application sidebar with nav groups docs
Input OTP One-time-password digit input group docs
Collapsible Single collapsible section (simpler than Accordion) docs
Resizable Drag-to-resize panel layout docs
Scroll Area Custom scrollbar container docs
Gallery Responsive image grid with optional lightbox docs
Chat Bubble Styled message bubble for chat or comment threads docs
Speed Dial Floating action button that expands into sub-actions docs
Device Mockup Phone or browser frame for marketing screenshots docs
QR Code QR code display from a given value docs
Timeline Vertical timeline with event items docs
Toaster Stacked toast notifications (Sonner-style) docs
Chart Chart.js adapter — bar, line, pie, doughnut, radar, polar area docs
Picture <picture> + <source> for art direction and modern formats (AVIF/WebP) docs
Video <video> + <source> with poster, controls, and caption tracks docs
Figure <figure> + <figcaption> wrapper for media content docs
Image Responsive <img> with srcset / sizes docs
Audio <audio> + <source> with optional transcript link docs
Iframe Sandboxed embed wrapper with required title and lazy loading docs
WYSIWYG Rich-text editor — Trix (default) or Quill adapter docs
Map / Area Image map with clickable <area> regions docs
Embed Third-party embeds — YouTube, Vimeo, Spotify, Google Maps, Yandex Maps, Loom, SoundCloud, X, Telegram, Facebook docs

See ROADMAP.md for the full component list organised by phase.

Customisation

See docs/customization.md for the full guide covering:

  • Design tokens (OKLCH colors, radius) — change the whole palette in one file
  • Editing component constants — add variants, change classes
  • Per-instance class: overrides — append utilities without touching the file
  • Full brand theming example

Development

bin/setup          # install dependencies
bundle exec rake   # run tests + linter
bin/console        # interactive prompt

To run tests against a specific Rails version:

bundle exec appraisal rails-8.1 rake test

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/alec-c4/view_primitives.

License

MIT License. See LICENSE.txt.