Shadwire
Componentes

Select

Exibe uma lista de opções para o usuário escolher — disparada por um botão.

Instalação

O Shadwire segue o modelo open-code do shadcn/ui: o código-fonte do componente é copiado para a sua aplicação e passa a ser seu. Instale com a CLI:

shadwire add select --yes

O item select do registry instala estes arquivos:

  • app/components/ui_component.rb
  • app/components/ui/select_component.rb
  • app/components/ui/select/trigger_component.rb
  • app/components/ui/select/value_component.rb
  • app/components/ui/select/content_component.rb
  • app/components/ui/select/item_component.rb
  • app/components/ui/select/group_component.rb
  • app/components/ui/select/label_component.rb
  • app/components/ui/select/separator_component.rb
  • app/components/ui/icon_component.rb
  • app/helpers/ui/select_helper.rb
  • app/helpers/ui/icon_helper.rb
  • app/javascript/controllers/ui_select_controller.js
  • vendor/shadwire/shadwire.css

Este componente usa Stimulus: a aplicação precisa de importmap-rails e stimulus-rails com carregamento automático de controllers.

Ainda não instalou a CLI? gem install shadwire e depois shadwire init.

Uso

O controller ui-select segue o padrão select-only combobox da APG: o foco permanece no gatilho (role="combobox") e a opção ativa é anunciada por aria-activedescendant. A seleção atualiza um input hidden e dispara change.

<%= ui_select(name: "fruit", placeholder: "Selecione") do %>
  <%= ui_select_trigger { ui_select_value } %>
  <%= ui_select_content do %>
    <%= ui_select_item(value: "apple") { "Maçã" } %>
    <%= ui_select_item(value: "banana") { "Banana" } %>
  <% end %>
<% end %>

Ou renderize os componentes diretamente:

<%= render Ui::SelectComponent.new(name: "fruit", value: "banana") do %>
  <%= render Ui::Select::TriggerComponent.new do %>
    <%= render Ui::Select::ValueComponent.new %>
  <% end %>
  <%= render Ui::Select::ContentComponent.new do %>
    <%= render Ui::Select::ItemComponent.new(value: "banana") do %>
      Banana
    <% end %>

Composição

Select (data-controller="ui-select", hidden input)
|-- Select::Trigger (role="combobox") > Select::Value + chevron
`-- Select::Content (role="listbox")
    `-- Select::Group > Select::Label + Select::Item (role="option")
        Select::Separator

Exemplos

Padrão

Combobox APG: o foco fica no gatilho, setas/typeahead navegam e a opção ativa usa aria-activedescendant.

<%= ui_select(name: "fruit", placeholder: "Selecione uma fruta", class: "w-[200px]") do %>
  <%= ui_select_trigger(class: "w-full") do %>
    <%= ui_select_value %>
  <% end %>
  <%= ui_select_content do %>
    <%= ui_select_item(value: "apple") { "Maçã" } %>
    <%= ui_select_item(value: "banana") { "Banana" } %>
    <%= ui_select_item(value: "blueberry") { "Mirtilo" } %>

Grupos

Agrupe opções com label e separador; itens podem ser desabilitados.

<%= ui_select(name: "timezone", value: "est", placeholder: "Selecione um fuso", class: "w-[240px]") do %>
  <%= ui_select_trigger(class: "w-full") do %>
    <%= ui_select_value %>
  <% end %>
  <%= ui_select_content do %>
    <%= ui_select_group do %>
      <%= ui_select_label { "América do Norte" } %>
      <%= ui_select_item(value: "est") { "Horário do Leste (EST)" } %>

Com form_with

O valor vai num input hidden (name:). O required nativo não se aplica — valide no servidor.

O valor é submetido por um input hidden — valide no servidor.

<%= form_with url: "#", scope: :profile do |form| %>
  <div class="grid w-[240px] gap-2">
    <%= ui_label(for: "profile-role-trigger") { "Função" } %>
    <%= ui_select(name: form.field_name(:role), value: "member", placeholder: "Selecione", class: "w-full") do %>
      <%= ui_select_trigger(id: "profile-role-trigger", class: "w-full") do %>
        <%= ui_select_value %>
      <% end %>
      <%= ui_select_content do %>

Referência da API

Todas as partes aceitam class / class_name e **attrs.

Componente Argumento Padrão Descrição
Select name nil Nome do input hidden para submissão em formulários.
Select value nil Valor inicialmente selecionado.
Select placeholder nil Texto exibido quando nada está selecionado.
Select::Trigger size :default :default ou :sm.
Select::Item value: (obrigatório), disabled Valor da opção; itens desabilitados são pulados na navegação.