Docs
Components
Accordion
Accordion
A vertically stacked set of interactive headings that each reveal a section of content.
Yes. It adheres to the WAI-ARIA design pattern.
Yes. It comes with default styles that matches the other components' aesthetic.
Yes. It's animated by default, but you can disable it if you prefer.
<%= accordion(type: 'single', collapsible: true, class: 'w-full') do %>
<%= accordion_item(value: 'item-1') do %>
<%= accordion_trigger do %>
Is it accessible?
<% end %>
<%= accordion_content do %>
Yes. It adheres to the WAI-ARIA design pattern.
<% end %>
<% end %>
<%= accordion_item(value: 'item-2') do %>
<%= accordion_trigger do %>
Is it styled?
<% end %>
<%= accordion_content do %>
Yes. It comes with default styles that matches the other components' aesthetic.
<% end %>
<% end %>
<%= accordion_item(value: 'item-3') do %>
<%= accordion_trigger do %>
Is it animated?
<% end %>
<%= accordion_content do %>
Yes. It's animated by default, but you can disable it if you prefer.
<% end %>
<% end %>
<% end %>
Installation
1
Copy and paste the following code into your project.
Create a new file in
app/components/ui/accordion_component.rb
and paste the following code:# frozen_string_literal: true
module Ui
class AccordionComponent < ViewComponent::Base
def initialize(type: 'single', collapsible: true, class_name: nil, **options)
super
@type = type
@collapsible = collapsible
@class_name = class_name
@options = options
end
def call
tag.div(class: accordion_classes, data: accordion_data, **@options) do
content
end
end
private
def accordion_classes
"#{@class_name}"
end
def accordion_data
{
controller: 'accordion',
accordion_type_value: @type,
accordion_collapsible_value: @collapsible
}
end
end
class AccordionItemComponent < ViewComponent::Base
def initialize(value:, default_open: false, class_name: nil, **options)
super
@value = value
@default_open = default_open
@class_name = class_name
@options = options
end
def call
tag.div(class: item_classes, data: item_data, **@options) do
content
end
end
private
def item_classes
"flex flex-col border-b border-border #{@class_name}"
end
def item_data
{
accordion_target: 'item',
value: @value,
state: @default_open ? 'open' : 'closed',
accordion_default_open_value: @default_open
}
end
end
class AccordionTriggerComponent < ViewComponent::Base
def initialize(class_name: nil, **options)
super
@class_name = class_name
@options = options
end
def call
tag.button(class: trigger_classes, data: trigger_data, **@options) do
safe_join([
content,
chevron_icon
])
end
end
private
def trigger_classes
"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180 #{@class_name}"
end
def trigger_data
{
accordion_target: 'trigger',
action: 'click->accordion#toggle'
}
end
def chevron_icon
tag.svg(xmlns: 'http://www.w3.org/2000/svg', width: '24', height: '24', viewBox: '0 0 24 24', fill: 'none',
stroke: 'currentColor', stroke_width: '2', stroke_linecap: 'round', stroke_linejoin: 'round', class: 'h-4 w-4 shrink-0 transition-transform duration-200') do
tag.polyline(points: '6 9 12 15 18 9')
end
end
end
class AccordionContentComponent < ViewComponent::Base
def initialize(class_name: nil, **options)
super
@class_name = class_name
@options = options
end
def call
tag.div(class: content_classes, data: content_data, style: content_style, **@options) do
tag.div(class: 'pb-4 pt-0') do
content
end
end
end
private
def content_classes
"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down #{@class_name}"
end
def content_data
{
accordion_target: 'content'
}
end
def content_style
'max-height: 0px;'
end
end
end
2
Update tailwind.config.js
Add the following animations to your
tailwind.config.js
file:module.exports = {
theme: {
extend: {
keyframes: {
'accordion-down': {
from: { height: '0' },
to: { height: 'var(--radix-accordion-content-height)' },
},
'accordion-up': {
from: { height: 'var(--radix-accordion-content-height)' },
to: { height: '0' },
},
},
animation: {
'accordion-down': 'accordion-down 0.2s ease-out',
'accordion-up': 'accordion-up 0.2s ease-out',
},
},
},
};
Coming soon.
Usage
<%= accordion(type: 'single', collapsible: true, class: 'w-full') do %>
<%= accordion_item(value: 'item-1') do %>
<%= accordion_trigger do %>
Is it accessible?
<% end %>
<%= accordion_content do %>
Yes. It adheres to the WAI-ARIA design pattern.
<% end %>
<% end %>
<%= accordion_item(value: 'item-2') do %>
<%= accordion_trigger do %>
Is it styled?
<% end %>
<%= accordion_content do %>
Yes. It comes with default styles that matches the other components' aesthetic.
<% end %>
<% end %>
<%= accordion_item(value: 'item-3') do %>
<%= accordion_trigger do %>
Is it animated?
<% end %>
<%= accordion_content do %>
Yes. It's animated by default, but you can disable it if you prefer.
<% end %>
<% end %>
<% end %>