Rails

Get started using Primer ViewComponents in your Rails application.
This library is under active pre-1.0 development. Breaking changes are likely in patch releases.

Introduction

Primer ViewComponents is an implementation of the Primer Design System for Ruby on Rails, built using ViewComponent.

New to ViewComponent? Check out this summary for an explanation of how they work.

Background

In recent years the Rails front-end landscape has become fairly complex. In the past, the mechanism for delivering JavaScript and CSS from a Rails app was the asset pipeline, powered by the sprockets and sprockets-rails gems. The asset pipeline was responsible for compiling, minifying, digesting, and serving assets, making it an all-in-one solution.

In later versions of Rails, the asset pipeline was superceded by Webpack via the webpacker gem. Webpack is highly configurable and capable of handling JavaScript and CSS via plugins. Out of the box, Rails only configures Webpack to handle JavaScript, continuing to rely on the asset pipeline for CSS.

In version 7, the Rails project introduced several new gems: jsbundling-rails, cssbundling-rails, and propshaft. Rather than provide the deep integration with the Rails framework their predecessors provided, these gems delegate to command-line tools written in other languages (usually JavaScript) to process JavaScript and CSS. jsbundling-rails supports bun, esbuild, rollup, and webpack as a legacy option. cssbundling-rails supports tailwind, bootstrap, bulma, postcss, and sass. Rails auto-generates entries in package.json for build and build:css scripts which compile JavaScript and CSS respectively.

Propshaft is a replacement for the asset pipeline (Sprockets) that offers a reduced set of features suitable for serving static assets that don't require a build step.

All of these are available to Rails devs, but require slightly different setups. The rest of this guide describes the setup for each in detail.

How to use this guide

This guide is designed to get your Rails app up and running with primer_view_components and offers sub-sections for each of the technologies referenced above. Generally speaking, follow these steps:

  1. Follow the list of common steps below.
  2. Find the sub-section for your app's front-end setup.
    1. For all-in-one solutions, follow the sub-section for Sprockets or Propshaft.
    2. Otherwise, follow the sub-sections for your JavaScript bundler and CSS bundler respectively.

Common steps

  1. Install the primer_view_components gem. You can add it to your Gemfile and run bundle install or run bundle add primer_view_components.

  2. Install the @primer/view-components, @primer/css, and @primer/primitives JavaScript packages from NPM using yarn (eg. yarn add @primer/view-components, etc). If your application doesn't have a package.json, install yarn via npm install -g yarn, then run yarn init. If you're using Bun, run bun init instead.

  3. Add the following lines to the very bottom of config/application.rb:

    require "view_component"
    require "primer/view_components"

All-in-one solutions

Sprockets

  1. Add your node_modules/ directory to Sprocket's load path by adding the following line to config/application.rb:

    config.assets.paths << Rails.root.join("node_modules")
  2. If it's not already there, add the following line to the Sprockets manifest at app/assets/config/manifest.js. This ensures Sprockets will precompile all the .js files in the app/javascript/ directory:

    //= link_directory ../javascript .js
  3. Inside app/javascript/application.js (create it if it doesn't exist), require primer_view_component's pre-bundled JavaScript file. Sprockets knows about this file because we added node_modules/ to its load path earlier:

    //= require @primer/view-components/app/assets/javascripts/primer_view_components.js
  4. Add the following lines to app/assets/stylesheets/application.css. These lines import shared CSS styles from @primer/css, primer_view_component's CSS styles, and a bunch of CSS variables from @primer/primitives. Notice we're also importing several color themes named "light" and "dark." The full list of supported themes is available in the Primer CSS documentation.

    //= require @primer/css/dist/primer.css
    //= require @primer/view-components/app/assets/styles/primer_view_components.css
    //= require @primer/primitives/dist/css/primitives.css
    //= require @primer/primitives/dist/css/functional/themes/light.css
    //= require @primer/primitives/dist/css/functional/themes/dark.css
  5. Add the following inside the <head></head> tags in app/views/layouts/application.html.erb:

    <%= javascript_include_tag "application", "data-turbo-track": "reload" %>
  6. Also in app/views/layouts/application.html.erb, add the following attributes to the <body> tag. If you chose to bundle different themes, use the names of those themes instead:

    <body data-color-mode="light" data-light-theme="light" data-dark-theme="dark">

Propshaft

  1. Add your node_modules/ directory to Propshaft's load path by adding the following line to config/application.rb:

    config.assets.paths << Rails.root.join("node_modules")
  2. Add the following inside the <head></head> tags in app/views/layouts/application.html.erb. These lines request primer_view_component's JavaScript code, shared CSS styles from @primer/css, primer_view_component's CSS styles, and a bunch of CSS variables from @primer/primitives. Notice we're also pulling in several color themes named "light" and "dark." The full list of supported themes is available in the Primer CSS documentation.

    <%= stylesheet_link_tag "@primer/css/dist/primer.css", "data-turbo-track": "reload" %>
    <%= stylesheet_link_tag "@primer/view-components/app/assets/styles/primer_view_components.css", "data-turbo-track": "reload" %>
    <%= stylesheet_link_tag "@primer/primitives/dist/css/primitives.css", "data-turbo-track": "reload" %>
    <%= stylesheet_link_tag "@primer/primitives/dist/css/functional/themes/light.css", "data-turbo-track": "reload" %>
    <%= stylesheet_link_tag "@primer/primitives/dist/css/functional/themes/dark.css", "data-turbo-track": "reload" %>
    <%= javascript_include_tag "@primer/view-components/app/assets/javascripts/primer_view_components.js", "data-turbo-track": "reload" %>
  3. Also in app/views/layouts/application.html.erb, add the following attributes to the <body> tag. If you chose to bundle different themes, use the names of those themes instead:

    <body data-color-mode="light" data-light-theme="light" data-dark-theme="dark">

JavaScript bundlers

Rails 7 supports a number of JavaScript bundlers that all work in a similar fashion. JavaScript packages are installed via yarn, imported into an entrypoint file, and served to the browser.

Import maps

Unfortunately at the time of this writing (June 2024), it is not possible to use primer_view_components with import maps. A number of primer_view_component's JavaScript dependencies attempt to import paths that the import map isn't expecting (eg. tab-container-element).

Webpack

While Webpack can bundle both CSS and JavaScript, Rails applications that use the webpacker gem are only equipped to bundle JavaScript by default.

  1. Add the following line to app/javascript/application.js:

    import "@primer/view-components"
  2. Modify webpack.config.js by setting the output -> iife option to false. This will prevent Webpack from wrapping the bundled code in an Immediately Invoked Function Expression (IIFE), which prevents defining the custom elements primer_view_components needs to work properly:

    module.exports = {
    // ...
    output: {
    iife: false
    }
    // ...
    }

esbuild

  1. Add the following line to app/javascript/application.js:

    import "@primer/view-components"

Rollup

  1. Add the following line to app/javascript/application.js:

    import "@primer/view-components"
  2. When Rollup runs, you might see a warning of the form (!) "this" has been rewritten to "undefined" printed to the console. The warning can safely be ignored. To prevent it from printing to the console, add an onwarn function to the config in rollup.config.js:

    export default {
    // ...
    onwarn: (warning, warn) => {
    if (warning.code === "THIS_IS_UNDEFINED") return
    warn(warning)
    }
    }

Vite

The steps below assume you've installed the vite_rails gem and run the installer.

  1. Add the following line to app/frontend/entrypoints/application.js:

    import "@primer/view-components"

Bun

Bun is an up-and-coming, fast, all-in-one JavaScript toolkit.

  1. Add the following line to app/frontend/entrypoints/application.js:

    import "@primer/view-components"

CSS bundlers

Rails 7 supports a number of CSS bundlers that all work in a similar fashion.

postcss

  1. Add the following lines to app/assets/stylesheets/application.postcss.css. These lines import shared CSS styles from @primer/css, primer_view_component's CSS styles, and a bunch of CSS variables from @primer/primitives. Notice we're also importing several color themes named "light" and "dark." The full list of supported themes is available in the Primer CSS documentation.

    @import "@primer/css/dist/primer.css";
    @import "@primer/view-components/app/assets/styles/primer_view_components.css";
    @import "@primer/primitives/dist/css/primitives.css";
    @import "@primer/primitives/dist/css/functional/themes/light.css";
    @import "@primer/primitives/dist/css/functional/themes/dark.css";
  2. In app/views/layouts/application.html.erb, add the following attributes to the <body> tag. If you chose to bundle different themes, use the names of those themes instead:

    <body data-color-mode="light" data-light-theme="light" data-dark-theme="dark">

sass / dartsass-rails

  1. Add the following lines to app/assets/stylesheets/application.sass.scss. These lines import shared CSS styles from @primer/css, primer_view_component's CSS styles, and a bunch of CSS variables from @primer/primitives. Notice we're also importing several color themes named "light" and "dark." The full list of supported themes is available in the Primer CSS documentation.

    @use "@primer/css/dist/primer.css";
    @use "@primer/view-components/app/assets/styles/primer_view_components.css";
    @use "@primer/primitives/dist/css/primitives.css";
    @use "@primer/primitives/dist/css/functional/themes/light.css";
    @use "@primer/primitives/dist/css/functional/themes/dark.css";
  2. In app/views/layouts/application.html.erb, add the following attributes to the <body> tag. If you chose to bundle different themes, use the names of those themes instead:

    <body data-color-mode="light" data-light-theme="light" data-dark-theme="dark">

Tailwind

Since Tailwind is implemented as a PostCSS plugin under the hood, it supports the @import directive for pulling in other CSS files.

  1. Add the following lines at the top of app/assets/stylesheets/application.tailwind.css (it's important they come before any of the lines that begin with @tailwind). These lines import shared CSS styles from @primer/css, primer_view_component's CSS styles, and a bunch of CSS variables from @primer/primitives. Notice we're also importing several color themes named "light" and "dark." The full list of supported themes is available in the Primer CSS documentation.

    @import "@primer/css/dist/primer.css";
    @import "@primer/view-components/app/assets/styles/primer_view_components.css";
    @import "@primer/primitives/dist/css/primitives.css";
    @import "@primer/primitives/dist/css/functional/themes/light.css";
    @import "@primer/primitives/dist/css/functional/themes/dark.css";
  2. In app/views/layouts/application.html.erb, add the following attributes to the <body> tag. If you chose to bundle different themes, use the names of those themes instead:

    <body data-color-mode="light" data-light-theme="light" data-dark-theme="dark">

Usage

Render Primer ViewComponents in Rails templates:

<%= render(Primer::Beta::Counter.new(count: 25)) %>

Dependencies

In addition to the dependencies declared in the gemspec, Primer ViewComponents assumes the presence of Primer CSS.

More information

See the primer/view_components repository for more information about how to use and contribute to Primer ViewComponents. For component-specific documentation, check out the Rails section of component guidelines (example: ActionList).