Rails - Importmap

How to install RubyUI within a Rails app that employs import maps

RubyUI
To take full advantage of RubyUI, the application is expected to be using TailwindCSS and Stimulus

Using RubyUI CLI

We provide a Ruby gem with useful generators to help you to setup RubyUI components in your apps.

1


Add RubyUI gem to your Gemfile

bundle add ruby_ui --group development --require false

2

Run the install command

rails g ruby_ui:install

Manual

You can install the dependencies manually if you prefer

1


Add Phlex Rails to your app

bundle add phlex-rails --github phlex-ruby/phlex-rails --branch main
Phlex compatibility
Note that RubyUI components target Phlex 2, but you can use them with Phlex 1.x as long as you are willing to adapt their code.

2


Install Phlex Rails

bin/rails g phlex:install

3


Install tailwind_merge

RubyUI components use tailwind_merge to avoid conflicts between TailwindCSS classes

bundle add tailwind_merge

4


Create RubyUI initializer

Add this code to config/initializers/ruby_ui.rb

module RubyUI
	extend Phlex::Kit
end

# Allow using RubyUI instead RubyUi
Rails.autoloaders.main.inflector.inflect(
	"ruby_ui" => "RubyUI"
)

# Allow using RubyUI::ComponentName instead Components::RubyUI::ComponentName
Rails.autoloaders.main.push_dir(
	"#{Rails.root}/app/components/ruby_ui", namespace: RubyUI
)

# Allow using RubyUI::ComponentName instead RubyUI::ComponentName::ComponentName
Rails.autoloaders.main.collapse(Rails.root.join("app/components/ruby_ui/*"))

5


Include RubyUI kit in your base component

Include RubyUI module in app/components/base.rb

module Components
	class Base < Phlex::HTML
		include Components
		include RubyUI

		...

6


Create the RubyUI base component

Every RubyUI component inherit from RubyUI::Base

Copy and paste the code snippet below into the app/components/ruby_ui/base.rb file.

require "tailwind_merge"

module RubyUI
	class Base < Phlex::HTML
		TAILWIND_MERGER = ::TailwindMerge::Merger.new.freeze unless defined?(TAILWIND_MERGER)

		attr_reader :attrs

		def initialize(**user_attrs)
			@attrs = mix(default_attrs, user_attrs)
			@attrs[:class] = TAILWIND_MERGER.merge(@attrs[:class]) if @attrs[:class]
		end

		private

		def default_attrs
			{}
		end
	end
end

7


Include RubyUI styles in your CSS

Include RubyUI styles in app/assets/stylesheets/application.tailwind.css

Your CSS file will look like this:

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 240 10% 3.9%;
    --card: 0 0% 100%;
    --card-foreground: 240 10% 3.9%;
    --popover: 0 0% 100%;
    --popover-foreground: 240 10% 3.9%;
    --primary: 240 5.9% 10%;
    --primary-foreground: 0 0% 98%;
    --secondary: 240 4.8% 95.9%;
    --secondary-foreground: 240 5.9% 10%;
    --muted: 240 4.8% 95.9%;
    --muted-foreground: 240 3.8% 46.1%;
    --accent: 240 4.8% 95.9%;
    --accent-foreground: 240 5.9% 10%;
    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 0 0% 98%;
    --border: 240 5.9% 90%;
    --input: 240 5.9% 90%;
    --ring: 240 5.9% 10%;
    --radius: 0.5rem;

    /* ruby_ui especific */
    --warning: 38 92% 50%;
    --warning-foreground: 0 0% 100%;
    --success: 87 100% 37%;
    --success-foreground: 0 0% 100%;
  }

  .dark {
    --background: 240 10% 3.9%;
    --foreground: 0 0% 98%;
    --card: 240 10% 3.9%;
    --card-foreground: 0 0% 98%;
    --popover: 240 10% 3.9%;
    --popover-foreground: 0 0% 98%;
    --primary: 0 0% 98%;
    --primary-foreground: 240 5.9% 10%;
    --secondary: 240 3.7% 15.9%;
    --secondary-foreground: 0 0% 98%;
    --muted: 240 3.7% 15.9%;
    --muted-foreground: 240 5% 64.9%;
    --accent: 240 3.7% 15.9%;
    --accent-foreground: 0 0% 98%;
    --destructive: 0 62.8% 30.6%;
    --destructive-foreground: 0 0% 98%;
    --border: 240 3.7% 15.9%;
    --input: 240 3.7% 15.9%;
    --ring: 240 4.9% 83.9%;

    /* ruby_ui especific */
    --warning: 38 92% 50%;
    --warning-foreground: 0 0% 100%;
    --success: 84 81% 44%;
    --success-foreground: 0 0% 100%;
  }
}

@layer base {
  * {
    @apply border-border;
  }

  body {
    @apply bg-background text-foreground;
    font-feature-settings: "rlig" 1, "calt" 1;

    /* docs specific */
    /* https://css-tricks.com/snippets/css/system-font-stack/ */
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  }
}

8


Install tailwindcss-animate plugin

Some RubyUI components utilize CSS animations to create smooth transitions.

bin/importmap pin tailwindcss-animate

9

Include RubyUI TailwindCSS theme

Include RubyUI theme config in config/tailwind.config.js

Your config file will look like this:

const defaultTheme = require('tailwindcss/defaultTheme')

module.exports = {
  content: [
    './app/views/**/*.rb', // Phlex views
    './app/components/**/*.rb', // Phlex components
    './public/*.html',
    './app/helpers/**/*.rb',
    './app/javascript/**/*.js',
    './app/views/**/*.{erb,haml,html,slim}'
  ],
  darkMode: ["class"],
  theme: {
    container: {
      center: true,
      padding: "2rem",
      screens: {
        "2xl": "1400px",
      },
    },
    extend: {
      colors: {
        border: "hsl(var(--border))",
        input: "hsl(var(--input))",
        ring: "hsl(var(--ring))",
        background: "hsl(var(--background))",
        foreground: "hsl(var(--foreground))",
        primary: {
          DEFAULT: "hsl(var(--primary))",
          foreground: "hsl(var(--primary-foreground))",
        },
        secondary: {
          DEFAULT: "hsl(var(--secondary))",
          foreground: "hsl(var(--secondary-foreground))",
        },
        destructive: {
          DEFAULT: "hsl(var(--destructive))",
          foreground: "hsl(var(--destructive-foreground))",
        },
        muted: {
          DEFAULT: "hsl(var(--muted))",
          foreground: "hsl(var(--muted-foreground))",
        },
        accent: {
          DEFAULT: "hsl(var(--accent))",
          foreground: "hsl(var(--accent-foreground))",
        },
        popover: {
          DEFAULT: "hsl(var(--popover))",
          foreground: "hsl(var(--popover-foreground))",
        },
        card: {
          DEFAULT: "hsl(var(--card))",
          foreground: "hsl(var(--card-foreground))",
        },
        /* ruby_ui especific */
        warning: {
          DEFAULT: "hsl(var(--warning))",
          foreground: "hsl(var(--warning-foreground))",
        },
        success: {
          DEFAULT: "hsl(var(--success))",
          foreground: "hsl(var(--success-foreground))",
        },
      },
      borderRadius: {
        lg: `var(--radius)`,
        md: `calc(var(--radius) - 2px)`,
        sm: "calc(var(--radius) - 4px)",
      },
      fontFamily: {
        sans: ["var(--font-sans)", ...defaultTheme.fontFamily.sans],
      },
    },
  },
  plugins: [
    require('@tailwindcss/forms'),
    require('@tailwindcss/typography'),
    require('@tailwindcss/container-queries'),
    require("../vendor/javascript/tailwindcss-animate")
  ]
}