ComponentsThemes
Palette
Default
Stone
Rose
Blue
Green
Violet
Yellow
Orange
6

← Components

Collapsible

Toggle the visibility of a content region with a smooth height animation.

Installation

bin/rails g wabi:add collapsible

Example

Source

app/components/ui/collapsible.rb

# frozen_string_literal: true

require "date" # Phlex 2.4 references Date/Time constants lazily when rendering data:{} hashes

module Components
  module UI
    class Collapsible < Wabi::Base
      def initialize(id: nil, open: false, disabled: false, **attrs)
        @id       = id
        @open     = open
        @disabled = disabled
        @attrs    = attrs
      end

      def view_template(&block)
        user_class = @attrs.delete(:class)
        div(
          id: @id,
          data: {
            controller: "wabi--collapsible",
            "wabi--collapsible-open-value":     @open.to_s,
            "wabi--collapsible-disabled-value": @disabled.to_s,
          },
          class: merge_class("w-full", user_class)
        ) do
          yield if block_given?
        end
      end
    end
  end
end

app/components/ui/collapsible_trigger.rb

# frozen_string_literal: true

require "date" # Phlex 2.4 references Date/Time constants lazily when rendering data:{} hashes

module Components
  module UI
    class CollapsibleTrigger < Wabi::Base
      def initialize(**attrs)
        @attrs = attrs
      end

      def view_template(&block)
        user_class = @attrs.delete(:class)
        button(
          type: "button",
          data: { "wabi--collapsible-target": "trigger" },
          class: merge_class(
            "inline-flex items-center justify-between gap-2 text-sm font-medium " \
            "ring-offset-background focus-visible:outline-none focus-visible:ring-2 " \
            "focus-visible:ring-ring focus-visible:ring-offset-2 " \
            "disabled:pointer-events-none disabled:opacity-50",
            user_class
          )
        ) do
          yield if block_given?
        end
      end
    end
  end
end

app/components/ui/collapsible_content.rb

# frozen_string_literal: true

require "date" # Phlex 2.4 references Date/Time constants lazily when rendering data:{} hashes

module Components
  module UI
    class CollapsibleContent < Wabi::Base
      def initialize(**attrs)
        @attrs = attrs
      end

      def view_template(&block)
        user_class = @attrs.delete(:class)
        div(
          data: { "wabi--collapsible-target": "content" },
          "data-state": "closed",
          class: merge_class(
            "grid grid-rows-[0fr] transition-[grid-template-rows] duration-200 ease-out " \
            "motion-reduce:transition-none data-[state=open]:grid-rows-[1fr]",
            user_class
          )
        ) do
          div(class: "overflow-hidden") do
            yield if block_given?
          end
        end
      end
    end
  end
end

Accessibility

  • Trigger exposes aria-expanded and aria-controls; content has a matching id.
  • Height animation respects prefers-reduced-motion.