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

Date Picker

Um Popover com um Calendar dentro. Não existe Ui::DatePickerComponent: você mesmo junta as duas peças.

Instalação

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

shadwire add date-picker --yes

O item date-picker do registry instala estes arquivos:

  • app/components/ui_component.rb
  • app/javascript/controllers/ui_date_picker_controller.js
  • vendor/shadwire/shadwire.css

Este componente usa Stimulus, então 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 ui_calendar é quem guarda o valor: ele grava a data escolhida num input escondido (name:) e dispara ui-calendar:change. O controller ui-date-picker escuta esse evento, mostra a data formatada no gatilho e fecha o popover. Ele só cuida da exibição: sem ele, o picker continua funcionando, mas o gatilho não mostra o que foi escolhido.

<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. No Tailwind v4, o ! vai no fim da classe.

Composição

data-controller="ui-date-picker"   the wiring: formats the label, parses what is typed, closes the popover
`-- Popover
    |-- Popover::Trigger           the visible field: a Button or an InputGroup
    |   `-- [data-ui-date-picker-target="label" | "input"]
    `-- Popover::Content (w-auto! p-0!)
        `-- Calendar               name:/end_name: write the value into the form

Exemplos

Os oito arranjos que o shadcn/ui documenta, traduzidos para ViewComponent + Stimulus.

Padrão

Um botão que abre o calendário num popover e depois mostra a data escolhida.

<%# Date Picker = Popover + Calendar (a recipe, not a new component).
    The ui-date-picker controller writes the chosen date into the label and closes the popover. %>
<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>

Com rótulo

O mesmo gatilho dentro de um Field, associado ao rótulo por id.

<%# The trigger is an ordinary button, so `for:`/`id:` tie it to the field label. %>
<%= ui_field(class: "w-48", data: { controller: "ui-date-picker" }) do %>
  <%= ui_field_label(for: "checkin") { "Date" } %>
  <%= ui_popover do %>
    <%= ui_popover_trigger(id: "checkin", variant: :outline, class: "justify-start font-normal") do %>
      <span data-ui-date-picker-target="label" data-empty="true" class="data-[empty=true]:text-muted-foreground">
        Pick a date
      </span>

Intervalo

Duas datas num só gatilho. O popover fecha depois da segunda data, não da primeira.

<%# `mode: :range` records both ends: `name:` is the start, `end_name:` the finish. %>
<%= ui_field(class: "w-72", data: { controller: "ui-date-picker", ui_date_picker_format_value: "medium" }) do %>
  <%= ui_field_label(for: "stay") { "Length of stay" } %>
  <%= ui_popover do %>
    <%= ui_popover_trigger(id: "stay", variant: :outline, class: "justify-start gap-2 px-2.5 font-normal") do %>
      <%= ui_icon("calendar", class: "opacity-50") %>
      <span data-ui-date-picker-target="label" data-empty="true" class="truncate data-[empty=true]:text-muted-foreground">
        Pick the dates

Data de nascimento

Selects de mês e ano na legenda e max: hoje, já que ninguém nasce no futuro.

<%# `caption_layout: :dropdown` swaps the month label for month and year selects —
    essential when the target is decades away. `max:` bounds the calendar and,
    with it, the range offered in the year select. %>
<%= ui_field(class: "w-52", data: { controller: "ui-date-picker", ui_date_picker_format_value: "short" }) do %>
  <%= ui_field_label(for: "born-on") { "Date of birth" } %>
  <%= ui_popover do %>
    <%= ui_popover_trigger(id: "born-on", variant: :outline, class: "justify-between font-normal") do %>
      <span data-ui-date-picker-target="label" data-empty="true" class="data-[empty=true]:text-muted-foreground">

Com campo de texto

Digite a data ou escolha no calendário. O que você digita é interpretado, e o campo mostra a data formatada. ↓ abre o popover.

<%# Text field + calendar: whatever is typed gets parsed and moves the calendar
    to that date; whatever is picked in the calendar comes back formatted into
    the field. ↓ in the field opens the popover. %>
<%= ui_field(class: "w-60", data: { controller: "ui-date-picker" }) do %>
  <%= ui_field_label(for: "subscribed-on") { "Subscription date" } %>
  <%= ui_input_group do %>
    <%= ui_input_group_input(
          id: "subscribed-on",

Data e hora

O picker define o dia e um input type="time" nativo define a hora.

<%# Date and time are two fields: the picker settles the day, a native
    `input type="time"` settles the hour. The browser's own indicator is hidden
    so it does not compete with the field's icon. %>
<div class="flex max-w-xs gap-4">
  <%= ui_field(data: { controller: "ui-date-picker" }) do %>
    <%= ui_field_label(for: "meeting-on") { "Date" } %>
    <%= ui_popover do %>
      <%= ui_popover_trigger(id: "meeting-on", variant: :outline, class: "w-36 justify-between font-normal") do %>

Linguagem natural

Entende "hoje", "amanhã", "em 2 semanas" e "próxima sexta". A lista de frases fica no controller, então você pode acrescentar as suas.

Your post goes out on .

<%# `natural_language_value: true` turns on the controller's relative vocabulary:
    "today", "tomorrow", "in 2 weeks", "next friday" — alongside the 08/01/2026,
    2026-08-01 and "August 1, 2026" formats. The phrase table is your code: edit
    the controller to suit the language you publish in. %>
<%= ui_field(class: "max-w-xs", data: { controller: "ui-date-picker", ui_date_picker_natural_language_value: "true" }) do %>
  <%= ui_field_label(for: "publish-on") { "Schedule publication" } %>
  <%= ui_input_group do %>
    <%= ui_input_group_input(

RTL

dir: :rtl espelha a grade, as setas e as teclas ←/→; month_names:/day_names: traduzem a legenda.

<%# `dir: :rtl` mirrors the grid, the navigation arrows and the ←/→ keys.
    `month_names:`/`day_names:` translate the caption and the column headers;
    `lang` and `locale-value` take care of the formatted date and the ARIA labels. %>
<% month_names = %w[يناير فبراير مارس أبريل مايو يونيو يوليو أغسطس سبتمبر أكتوبر نوفمبر ديسمبر] %>
<% day_names = %w[أحد إثنين ثلاثاء أربعاء خميس جمعة سبت] %>

<div dir="rtl" lang="ar" data-controller="ui-date-picker" data-ui-date-picker-locale-value="ar-EG">
  <%= ui_popover do %>

Referência da API

O que o calendário aceita está em Calendar. A tabela abaixo cobre só o controller que liga os dois: os atributos data-* no elemento que envolve o popover e o campo.

Atributo Padrão Descrição
format-value long full, long, medium, short ou iso.
locale-value — BCP 47 (pt-BR, ar-EG). Vazio segue o idioma do navegador.
separator-value  –  O que separa as duas pontas de um intervalo no rótulo.
date-order-value dmy Como ler 01/06/2026 ao digitar. mdy para o formato americano.
close-on-select-value true Fecha o popover ao escolher. Em mode: :range, só depois da segunda data.
natural-language-value false Aceita frases relativas (“amanhã”, “em 2 semanas”, “próxima sexta”) no campo de texto.
target="label" — O elemento cujo texto vira a data escolhida; recebe data-empty enquanto está vazio.
target="input" — Um campo de texto editável: o que você digita é interpretado, e ↓ abre o popover.
target="preview" — Mostra, se você quiser, a data interpretada numa linha de apoio abaixo do campo.