Date Picker
A Popover + Calendar composition for picking a single date.
Installation
npx kosmesis add date-pickerpnpm dlx kosmesis add date-pickeryarn dlx kosmesis add date-pickerbunx kosmesis add date-pickerInstall the following dependencies:
npm install @morphos/overlayspnpm add @morphos/overlaysyarn add @morphos/overlaysbun add @morphos/overlaysThis component builds on other Kosmesis components — install these first (via kosmesis add or this same manual process on their own pages): button, calendar, popover.
Copy and paste the following code into your project.
import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import { type Popover, PopoverTrigger } from "@morphos/overlays";import { buttonVariants } from "./button";import { Calendar, type CalendarState } from "./calendar";import { PopoverContent } from "./popover";import { cn } from "@/lib/utils";export interface DatePickerProps { popover: Popover; calendar: CalendarState; placeholder?: string; class?: string;}/** * A composition, not a new primitive: `Popover` (Morphos) + `Calendar` (built from scratch above). * Instantiate both state objects once, same pattern as everything else: * * ```tsx * @State() popover = new Popover() * @State() calendar = new CalendarState({ onSelect: () => this.popover.closePopover() }) * ``` * * Morphos's `PopoverTrigger` always renders its own `<button>` (there's no `asChild` merge like * Radix's) — so the trigger is styled directly with `buttonVariants()` here instead of nesting a * separate `Button` inside it, which would produce invalid nested `<button>` elements. */@Component()export class DatePicker extends StatelessComponent<DatePickerProps> { render() { const { popover, calendar, placeholder = "Pick a date", class: cls } = this.props; return ( <> <PopoverTrigger popover={popover} class={cn(buttonVariants({ variant: "outline" }), "justify-start font-normal", cls)}> {() => { const date = calendar.selectedDate; return date ? date.toLocaleDateString() : placeholder; }} </PopoverTrigger> <PopoverContent popover={popover} class="w-auto p-0"> <Calendar state={calendar} class="border-none shadow-none" /> </PopoverContent> </> ); }}Install the following dependencies:
npm install @morphos/overlays @praxisjs/csspnpm add @morphos/overlays @praxisjs/cssyarn add @morphos/overlays @praxisjs/cssbun add @morphos/overlays @praxisjs/cssThis component builds on other Kosmesis components — install these first (via kosmesis add or this same manual process on their own pages): button, calendar, popover.
Copy and paste the following code into your project.
import { StatelessComponent } from "@praxisjs/core";import { cx, Stylesheet, Styled } from "@praxisjs/css";import { Component } from "@praxisjs/decorators";import { type Popover, PopoverTrigger } from "@morphos/overlays";import { ButtonStyles } from "./button";import { Calendar, type CalendarState } from "./calendar";import { PopoverContent } from "./popover";class DatePickerStyles extends Stylesheet { $trigger = this.css({ justifyContent: "flex-start", fontWeight: 400 }); $content = this.css({ width: "auto", padding: "0" });}export interface DatePickerProps { popover: Popover; calendar: CalendarState; placeholder?: string; class?: string;}/** * A composition, not a new primitive: `Popover` (Morphos) + `Calendar` (built from scratch above). * Instantiate both state objects once, same pattern as everything else: * * ```tsx * @State() popover = new Popover() * @State() calendar = new CalendarState({ onSelect: () => this.popover.closePopover() }) * ``` * * Morphos's `PopoverTrigger` always renders its own `<button>` (there's no `asChild` merge like * Radix's) — so the trigger is styled directly with `ButtonStyles` here instead of nesting a * separate `Button` inside it, which would produce invalid nested `<button>` elements. */@Component()export class DatePicker extends StatelessComponent<DatePickerProps> { @Styled(ButtonStyles) $btn!: ButtonStyles; @Styled(DatePickerStyles) $s!: DatePickerStyles; render() { const { popover, calendar, placeholder = "Pick a date", class: cls } = this.props; return ( <> <PopoverTrigger popover={popover} class={cx(this.$btn.$root, this.$btn.$variantOutline, this.$btn.$sizeDefault, this.$s.$trigger, cls)} > {() => { const date = calendar.selectedDate; return date ? date.toLocaleDateString() : placeholder; }} </PopoverTrigger> <PopoverContent popover={popover} class={this.$s.$content}> <Calendar state={calendar} /> </PopoverContent> </> ); }}Examples
Usage
import { Popover } from "@morphos/overlays";
import { CalendarState } from "@/components/ui/calendar";
import { DatePicker } from "@/components/ui/date-picker";
@Component()
class BookingForm extends StatefulComponent {
@State() popover = new Popover();
@State() calendar = new CalendarState({
onSelect: () => { this.popover.closePopover(); },
});
render() {
return <DatePicker popover={this.popover} calendar={this.calendar} />;
}
}This is a composition, not a new primitive — Popover (Morphos) +
Calendar (built from scratch). If you need a different trigger
style or a range picker, compose those two components directly instead of using DatePicker.