Shadwire

Buscar na documentação

Busque nas páginas da documentação e dos componentes por título e por conteúdo.

Começar
Introdução
Instalação
shadwire.json
Theming
Dark mode
Ferramentas
CLI
Agent skill
Registry
llms.txt
Guias
Composição
Estilização
Formulários
Ícones
Acessibilidade
Localização
Blocks
Visão geral
Componentes
Visão geral
Accordion
Alert
Alert Dialog
Aspect Ratio
Avatar
Badge
Breadcrumb
Button
Button Group
Calendar
Card
Carousel
Chart
Checkbox
Collapsible
Combobox
Command
Context Menu
Data Table
Date Picker
Dialog
Drawer
Dropdown Menu
Empty
Field
Hover Card
Icon
Input
Input Group
Input OTP
Item
Kbd
Label
Menubar
Native Select
Navigation Menu
Pagination
Popover
Progress
Radio Group
Resizable
Scroll Area
Select
Separator
Sheet
Sidebar
Skeleton
Slider
Sonner
Spinner
Switch
Table
Tabs
Textarea
Toggle
Toggle Group
Tooltip

Formulários

Monte cada linha do formulário com field e ligue os controles ao form_with você mesmo. Não existe form builder.

Envolva todo controle em ui_field

Não monte linhas de formulário com divs e utilitários de espaçamento. O field já cuida do rótulo, da descrição, da mensagem de erro e do espaço entre eles.

<%# Wrong %>
<div class="space-y-2">
  <%= ui_label(for: "email") { "Email" } %>
  <%= ui_input(type: :email, id: "email", name: "email") %>
  <p class="text-sm text-muted-foreground">We never share it.</p>
</div>
<%# Right %>
<%= ui_field do %>
  <%= ui_field_label(for: "email") { "Email" } %>
  <%= ui_input(type: :email, id: "email", name: "email") %>
  <%= ui_field_description { "We never share it." } %>
<% end %>

Todas as partes do field:

Helper Papel
ui_field A linha. Aceita orientation: :vertical (padrão), :horizontal ou :responsive.
ui_field_group Empilha vários campos com espaçamento consistente.
ui_field_set + ui_field_legend Agrupa checkboxes ou radios relacionados, em vez de uma div com um título.
ui_field_label O rótulo do campo.
ui_field_title / ui_field_description Texto de apoio acima e abaixo do controle.
ui_field_error A mensagem de erro, com role="alert".
ui_field_content Envolve o controle quando ele precisa de um container próprio.
ui_field_separator Divide seções dentro de um grupo.

Estado de validação

Passe invalid: true para o ui_field. Ele marca data-invalid e deixa o texto da linha em vermelho (a cor destructive). A mensagem vai em ui_field_error.

<%= ui_field(invalid: user.errors[:email].any?) do %>
  <%= ui_field_label(for: "email") { "Email" } %>
  <%= ui_input(type: :email, id: "email", name: "email",
               "aria-invalid": user.errors[:email].any?) %>
  <%= ui_field_error(errors: user.errors[:email]) %>
<% end %>

ui_field_error aceita conteúdo em bloco ou um array em errors:, e não renderiza nada quando os dois estão vazios, então dá para deixá-lo sempre no template, sem if.

Não existe integração com form builder

Não há f.ui_input. Os controles repassam qualquer atributo HTML para o elemento, então você mesmo os liga ao form_with:

<%= form_with(model: @user) do |form| %>
  <%= ui_field(invalid: @user.errors[:email].any?) do %>
    <%= ui_field_label(for: form.field_id(:email)) { "Email" } %>
    <%= ui_input(type: :email,
                 id: form.field_id(:email),
                 name: form.field_name(:email),
                 value: @user.email) %>
    <%= ui_field_error(errors: @user.errors[:email]) %>

form.field_name e form.field_id geram os nomes user[email] e user_email que o Rails espera, então os params chegam como de costume. O mesmo vale para ui_checkbox, ui_switch, ui_textarea, ui_select, ui_radio_group e ui_slider.

<%= hidden_field_tag form.field_name(:admin), "0", id: nil %>
<%= ui_checkbox(name: form.field_name(:admin), id: form.field_id(:admin),
                value: "1", checked: @user.admin?) %>

Escolhendo o controle

Situação Controle
Uma linha de texto ui_input
Várias linhas ui_textarea
Texto com prefixo, sufixo ou botão ui_input_group
Uma opção de uma lista longa ui_select, ou combobox se for preciso buscar
Uma entre poucas opções visíveis ui_radio_group
O seletor nativo no celular, sem JS ui_native_select
Várias escolhas independentes ui_checkbox
Duas a sete escolhas compactas ui_toggle_group
Configuração aplicada na hora ui_switch
Número aproximado ui_slider
Número exato ui_input(type: :number)
Data ou intervalo date-picker, ou ui_calendar inline
Código de uso único ui_input_otp

O date picker é uma receita

Não existe Ui::DatePickerComponent. Um campo de data é um ui_popover com um ui_calendar dentro, e o controller ui-date-picker mostra a data escolhida no gatilho e fecha o popover. O valor fica no calendário: passe name: e ele renderiza um input oculto, então a data é enviada como qualquer outro campo.

<div data-controller="ui-date-picker" data-ui-date-picker-format-value="long">
  <%= ui_popover do %>
    <%= ui_popover_trigger(variant: :outline, class: "w-[212px] justify-between font-normal") do %>
      <span data-ui-date-picker-target="label" data-empty="true"
            class="data-[empty=true]:text-muted-foreground">Pick a date</span>
      <%= ui_icon("chevron-down", class: "opacity-50") %>
    <% end %>
    <%= ui_popover_content(align: :start, class: "w-auto! p-0!") do %>

O popover precisa de w-auto! p-0!, porque o w-72 e o padding padrão deixam pouco espaço para o calendário. As variações são argumentos do calendário: mode: :range, caption_layout: :dropdown, dir: :rtl. bin/shadwire info date-picker lista todas, e a página do Date Picker mostra cada uma ao vivo.

Input group tem o próprio input

Dentro de ui_input_group, use os helpers do próprio grupo em vez de um ui_input comum.

<%# Wrong %>
<%= ui_input_group do %>
  <%= ui_input_group_addon { ui_icon("search") } %>
  <%= ui_input(name: "q") %>
<% end %>
<%# Right %>
<%= ui_input_group do %>
  <%= ui_input_group_addon { ui_icon("search") } %>
  <%= ui_input_group_input(name: "q", placeholder: "Search") %>
<% end %>