Rails

How to install and use Kaida components in your Ruby on Rails application.

Installation

  1. Install Tailwind CSS v4 in your Rails project:
  • Add to your Gemfile: ruby gem 'tailwindcss-rails', '4.0' gem 'tailwindcss-ruby', '4.0'
  • Run: bundle install
  • For more details: tailwindcss-rails documentation
  1. Copy the theme CSS variables to your app/assets/stylesheets/application.tailwind.css or app/assets/stylesheets/tailwind/application.css.

  2. Copy the component files into your project (e.g., app/javascript/components/).

Usage

Kaida components are divided into two types:

Components without JavaScript

Components like Button, Badge, Input, Card work with pure CSS/Tailwind. No JavaScript initialization needed — just copy the HTML:

<!-- app/views/components/_button.html.erb -->
<button
  name="button"
  type="button"
  class="flex gap-8px items-center justify-center whitespace-nowrap py-4px px-16px text-btn2 [&>svg]:w-16px [&>svg]:h-16px rounded-8px text-white dark:text-accent-900 border disabled:opacity-30 focus:shadow-[0_0_0_2px_#FFFFFF,0_0_0_4px_#0F172A] dark:focus:shadow-[0_0_0_2px_#2d2e33,0_0_0_4px_#FFFFFF] bg-accent-900 border-accent-900 hover:bg-accent-700 hover:border-accent-700 focus:bg-accent-700 focus:border-accent-700 active:bg-accent-500 active:border-accent-500 dark:bg-white dark:border-white dark:hover:bg-accent-200 dark:hover:border-accent-200 dark:focus:bg-accent-200 dark:focus:border-accent-200 dark:active:bg-accent-400 dark:active:border-accent-400"
  title="Get started">
  Get started
</button>

Components with JavaScript

Components like Accordion, Toast, Dropdown require JavaScript initialization.

Basic initialization

Copy the JS file to app/javascript/components/ and import in your entry file:

// app/javascript/application.js
import { initAccordions } from './components/accordion';

document.addEventListener('DOMContentLoaded', () => {
  initAccordions();
});

Then use in your views:

<div
  class="list-none"
  data-accordion="open"
  role="list">
  <!-- accordion items -->
</div>

Important: Call initAccordions() only once on page load. Multiple calls will create duplicate instances.

Using with Turbo

If you're using Turbo Drive/Turbo Frames, reinitialize after Turbo navigation:

// app/javascript/application.js
import { initAccordions } from './components/accordion';

function initKaida() {
  initAccordions();
  // init_other_components();
}

// Initial load
document.addEventListener('DOMContentLoaded', initKaida);

// Turbo navigation
document.addEventListener('turbo:load', initKaida);

Using with Import Maps (Rails 7+)

// config/importmap.rb
pin "accordion", to: "components/accordion.js"
// app/javascript/controllers/application.js
import { Controller } from "@hotwired/stimulus"
import { initAccordions } from "accordion"

export default class extends Controller {
  connect() {
    initAccordions();
  }
}

Example

Here's a complete example using the Accordion component:

<!-- app/views/pages/faq.html.erb -->
<div class="list-none" data-accordion="open" role="list">
  <li role="listitem">
    <button
      id="header-0"
      type="button"
      data-accordion-trigger="#panel-0"
      aria-expanded="false"
      aria-controls="panel-0"
      class="flex items-center justify-between gap-16px w-full pt-20px pb-20px px-24px text-h9 rtl:text-right border-t border-accent-200 dark:border-black-600 [&.active]:pb-12px will-change:padding-bottom [&>span]:will-change:opacity transition-all [&>span]:transition-all hover:[&>span]:opacity-70">
      <span>
        Text
      </span>
      <svg
        data-accordion-icon=""
        class="rotate-180 shrink-0"
        aria-hidden="true"
        width="24"
        height="24"
        viewbox="0 0 24 24"
        fill="none"
        xmlns="http://www.w3.org/2000/svg">
        <path
          d="M18 15L12 9L6 15"
          stroke="currentColor"
          stroke-width="1.5"
          stroke-linecap="round"
          stroke-linejoin="round">
        </path>
      </svg>
    </button>
    <div
      id="panel-0"
      role="region"
      aria-labelledby="header-0"
      class="hidden">
      <div class="px-24px pb-20px text-p2">
        <p>
          Description
        </p>
      </div>
    </div>
  </li>

  <li role="listitem">
    <button
      id="header-1"
      type="button"
      data-accordion-trigger="#panel-1"
      aria-expanded="false"
      aria-controls="panel-1"
      class="flex items-center justify-between gap-16px w-full pt-20px pb-20px px-24px text-h9 rtl:text-right border-t border-accent-200 dark:border-black-600 [&.active]:pb-12px will-change:padding-bottom [&>span]:will-change:opacity transition-all [&>span]:transition-all hover:[&>span]:opacity-70">
      <span>
        Text
      </span>
      <svg
        data-accordion-icon=""
        class="rotate-180 shrink-0"
        aria-hidden="true"
        width="24"
        height="24"
        viewbox="0 0 24 24"
        fill="none"
        xmlns="http://www.w3.org/2000/svg">
        <path
          d="M18 15L12 9L6 15"
          stroke="currentColor"
          stroke-width="1.5"
          stroke-linecap="round"
          stroke-linejoin="round">
        </path>
      </svg>
    </button>
    <div
      id="panel-1"
      role="region"
      aria-labelledby="header-1"
      class="hidden">
      <div class="px-24px pb-20px text-p2">
        <p>
          Description
        </p>
      </div>
    </div>
  </li>
</div>
// app/javascript/application.js
import { initAccordions } from './components/accordion';

document.addEventListener('DOMContentLoaded', () => {
  initAccordions();
});

Key points:

  • No JS components (Button, Badge, Input, Card, etc.) — just copy HTML to ERB/HAML
  • JS components (Accordion, Toast, Dropdown, etc.) — initialize on DOMContentLoaded
  • Use standard HTML attributes in Rails views (class, not className)
  • Initialize once to avoid duplicates
  • Turbo: Reinitialize on turbo:load event
  • Import Maps: Pin components in config/importmap.rb
  • Stimulus: Can wrap initialization in Stimulus controllers
  • Data attributes (data-accordion, data-accordion-trigger, etc.) remain the same