Kosmesis
Components

Date Picker

A Popover + Calendar composition for picking a single date.

Installation

npx kosmesis add date-picker
pnpm dlx kosmesis add date-picker
yarn dlx kosmesis add date-picker
bunx kosmesis add date-picker

Install the following dependencies:

npm install @morphos/overlays
pnpm add @morphos/overlays
yarn add @morphos/overlays
bun add @morphos/overlays

This 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.

date-picker.tsx
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/css
pnpm add @morphos/overlays @praxisjs/css
yarn add @morphos/overlays @praxisjs/css
bun add @morphos/overlays @praxisjs/css

This 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.

date-picker.tsx
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.

On this page