Skip to content

Instantly share code, notes, and snippets.

@khash
Last active August 5, 2024 21:09
Show Gist options
  • Save khash/0e862d19e45c46e4ca7f36484bc84519 to your computer and use it in GitHub Desktop.
Save khash/0e862d19e45c46e4ca7f36484bc84519 to your computer and use it in GitHub Desktop.
Dropdown Component with ViewComponents, TailwindCSS and Stimulus
<!-- app/components/dropdown/component.html.erb -->
<div class="relative inline-block text-left" data-controller="dropdown--component">
<div>
<button type="button"
class="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-indigo-500"
data-action="click->dropdown--component#toggleMenu"
aria-haspopup="true"
aria-expanded="true">
<%= @title %>
<!-- Heroicon name: solid/chevron-down -->
<svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
</div>
<div class="hidden origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 z-50"
data-dropdown--component-target="menu">
<div class="py-1" role="menu" aria-orientation="vertical" aria-labelledby="options-menu">
<% @items.each do |item| %>
<%= link_to item.title,
item.url,
role: "menuitem",
method: item.method,
class: "block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 #{item.selected ? 'font-semibold' : ''}" %>
<% end %>
</div>
</div>
</div>
# app/components/dropdown/component.rb
module Dropdown
class Component < ViewComponent::Base
def initialize(items:)
@items = items
title_item = items.find { |x| x.selected }
if title_item.nil?
title_item = items.first
items.first.selected = true
end
@title = title_item.title
end
end
class Item
attr_accessor :title
attr_accessor :selected
attr_accessor :url
attr_accessor :method
def initialize(title:, selected:, url:, method: :get)
@title = title
@selected = selected
@url = url
@method = method
end
end
end
// app/components/dropdown/component_controller.js
import {Controller} from 'stimulus';
export default class extends Controller {
static targets = ["menu"]
toggleMenu() {
this.menuTarget.classList.toggle('hidden');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment