Date Picker
A button that opens a calendar in a popover.
<datepicker.DatePicker id="date-empty" name="day" />Installation
Run the command in the app module.
gx add date-pickerThe command also installs calendar and popover.
The command writes these files.
| File | Path in the app |
|---|---|
DatePicker.gx |
ui/date-picker/DatePicker.gx |
DatePicker.fixtures.go |
ui/date-picker/DatePicker.fixtures.go |
styles.go |
ui/date-picker/styles.go |
Install calendar and popover first.
Copy each file to its path in the app. Change each import of a registry package to the path of that package in the app.
package datepicker
import "github.com/alternayte/gx/registry/calendar"
import "github.com/alternayte/gx/registry/popover"
props {
// Id is the id of the date input. A label points at it.
Id string
// Name is the form field name. The form sends the day as YYYY-MM-DD.
Name string = ""
// Value is the chosen day of the first render, as YYYY-MM-DD.
Value string = ""
// Min is the first day that a user can choose, as YYYY-MM-DD.
Min string = ""
// Max is the last day that a user can choose, as YYYY-MM-DD.
Max string = ""
// Placeholder is the text of the trigger with no chosen day.
Placeholder string = "Pick a date"
// Label is the accessible name of the date input.
Label string = "Date"
// WeekStart is the first day of the week: calendar.Sunday or calendar.Monday.
WeekStart calendar.WeekStart = calendar.Sunday
// Locale is the language of the month and day names, as a BCP 47 tag. Empty means the language of the page.
Locale string = ""
// Class adds classes to the root element.
Class string = ""
// Attrs adds HTML attributes to the date input.
Attrs gx.Attrs = nil
}
<div data-slot="date-picker" class={gx.Cx("inline-block", p.Class)}>
<popover.PopoverTrigger id={p.popoverID()} class={triggerClass}>
<span id={p.displayID()} data-empty={p.empty()} class={displayClass}>{p.text()}</span>
</popover.PopoverTrigger>
<popover.Popover id={p.popoverID()} align={popover.Start} class="w-auto p-0">
<calendar.Calendar id={p.Id} name={p.Name} value={p.Value} min={p.Min} max={p.Max} label={p.Label} weekStart={p.WeekStart} locale={p.Locale} display={p.displayID()} popover={p.popoverID()} class="border-0" attrs={p.Attrs} />
</popover.Popover>
</div>package datepicker
import (
"github.com/alternayte/gx"
"github.com/alternayte/gx/registry/calendar"
)
var DatePickerFixtures = gx.Fixtures[DatePickerProps]{
"Empty": {Id: "date-empty", Name: "day"},
"Chosen": {Id: "date-chosen", Name: "day", Value: "2026-10-14"},
"Limited": {Id: "date-limited", Name: "day", Value: "2026-10-14", Min: "2026-10-10", Max: "2026-10-20", WeekStart: calendar.Monday},
}// Package datepicker is a button that opens a calendar in a popover.
package datepicker
// triggerClass is the classes of the trigger button: as wide as a date and
// with its text at the start.
const triggerClass = "w-64 justify-start font-normal"
// displayClass is the classes of the text of the trigger. The placeholder
// is muted.
const displayClass = "truncate data-[empty=true]:text-muted-foreground"
// popoverID returns the id of the popover.
func (p DatePickerProps) popoverID() string { return p.Id + "-popover" }
// displayID returns the id of the element that shows the chosen day.
func (p DatePickerProps) displayID() string { return p.Id + "-display" }
// empty reports, as an attribute value, whether no day is chosen.
func (p DatePickerProps) empty() string {
if p.Value == "" {
return "true"
}
return "false"
}
// text returns the text of the trigger for the first render: the day as
// the server has it, or the placeholder. The calendar island writes the day
// in the language of the user.
func (p DatePickerProps) text() string {
if p.Value != "" {
return p.Value
}
// A props value that Go code makes has no default.
if p.Placeholder == "" {
return "Pick a date"
}
return p.Placeholder
}The theme must define these tokens: --muted-foreground.
Usage
<label for="due">Due date</label>
<datepicker.DatePicker id="due" name="due" value={p.Due} />
<datepicker.DatePicker id="start" name="start" min="2026-10-10" max="2026-10-20" placeholder="Start date" />The component is a popover with a calendar. The calendar holds a native <input type="date">, so a form sends the day as YYYY-MM-DD.
The button shows the chosen day in the language of the user. A choice closes the popover.
With no script the button opens the popover, and the popover shows the date input of the browser.
Examples
Empty
<datepicker.DatePicker id="date-empty" name="day" />Chosen
<datepicker.DatePicker id="date-chosen" name="day" value="2026-10-14" />Limited
<datepicker.DatePicker id="date-limited" name="day" value="2026-10-14" min="2026-10-10" max="2026-10-20" weekStart={calendar.Monday} />API reference
A tag sets a prop by its name with a lower-case first letter: Class is class.
datepicker.DatePicker
| Prop | Type | Default | Description |
|---|---|---|---|
Id |
string |
Required | Id is the id of the date input. A label points at it. |
Name |
string |
"" |
Name is the form field name. The form sends the day as YYYY-MM-DD. |
Value |
string |
"" |
Value is the chosen day of the first render, as YYYY-MM-DD. |
Min |
string |
"" |
Min is the first day that a user can choose, as YYYY-MM-DD. |
Max |
string |
"" |
Max is the last day that a user can choose, as YYYY-MM-DD. |
Placeholder |
string |
"Pick a date" |
Placeholder is the text of the trigger with no chosen day. |
Label |
string |
"Date" |
Label is the accessible name of the date input. |
WeekStart |
calendar.WeekStart |
calendar.Sunday |
WeekStart is the first day of the week: calendar.Sunday or calendar.Monday. |
Locale |
string |
"" |
Locale is the language of the month and day names, as a BCP 47 tag. Empty means the language of the page. |
Class |
string |
"" |
Class adds classes to the root element. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the date input. |
Do and do not
Do
- Give the date picker a
<label>for itsId. - Set
MinandMaxfor a range of valid days. The server checks the value too. - Use a
Placeholderthat names the date, for example "Start date".
Don't
- Do not use a date picker for a date of birth. Use three inputs or one text input.
- Do not put a date picker in a popover.
Keyboard
| Key | Action |
|---|---|
| Tab | Moves focus to the button. |
| Enter, Space | Opens the calendar from the button, or chooses the day that has the focus. |
| Arrow keys | Moves one day or one week in the calendar. |
| Page Up, Page Down | Moves one month back or forward. |
| Escape | Closes the calendar and moves focus to the button. |