Skip to content

DatePicker — usage examples

DatePicker ships as six pre-compiled, per-framework packages from a single .rozie source — install only the one for your framework (no Rozie toolchain, no build-time compile step). Each carries its engine + framework peers as peer dependencies, so you control their versions. The snippets below are the same idiomatic consumption code shown in each package's README; switch the tab to your framework.

Usage

tsx
import { useState } from 'react';
import { DatePicker } from '@rozie-ui/date-picker-react';

export function Demo() {
  const [date, setDate] = useState(''); // ISO YYYY-MM-DD, '' = no selection
  return (
    <DatePicker
      value={date}
      onValueChange={setDate}
      min="2026-01-01"
      onChange={(e) => console.log('picked:', e.value)}
    />
  );
}

// Custom header via the scoped #header slot (render-prop on React).
export function CustomHeaderDemo() {
  const [date, setDate] = useState('');
  return (
    <DatePicker value={date} onValueChange={setDate}>
      {{
        header: ({ label, prev, next }) => (
          <div className="my-header">
            <button onClick={prev}>Prev</button>
            <strong>{label}</strong>
            <button onClick={next}>Next</button>
          </div>
        ),
      }}
    </DatePicker>
  );
}

// Range selection: set selectionMode="range" and bind an object value
// { start, end }. React capitalizes the event prop → onRangeComplete.
export function RangeDemo() {
  const [range, setRange] = useState({ start: '', end: '' });
  // presetRanges: each range is a literal OR a () => { start, end } thunk.
  const iso = (d: Date) => d.toISOString().slice(0, 10);
  const presetRanges = [
    { label: 'Q1 2026', range: { start: '2026-01-01', end: '2026-03-31' } },
    { label: 'Last 7 days', range: () => ({ start: iso(new Date(Date.now() - 6 * 864e5)), end: iso(new Date()) }) },
  ];
  return (
    <DatePicker
      selectionMode="range"
      value={range}
      onValueChange={setRange}
      presetRanges={presetRanges}
      onRangeComplete={(e) => console.log('range:', e.value)}
    >
      {{
        // Override the default preset rail via the #presets slot (render-prop).
        presets: ({ presets, apply }) => (
          <div className="my-presets">
            {presets.map((p) => (
              <button key={p.label} onClick={() => apply(p.range)}>{p.label}</button>
            ))}
          </div>
        ),
      }}
    </DatePicker>
  );
}
vue
<script setup lang="ts">
import { ref } from 'vue';
import DatePicker from '@rozie-ui/date-picker-vue';

const date = ref(''); // ISO YYYY-MM-DD, '' = no selection
function onChange(e: { value: string }) {
  console.log('picked:', e.value);
}

// Range mode: value becomes a { start, end } object.
const range = ref({ start: '', end: '' });
const iso = (d: Date) => d.toISOString().slice(0, 10);
const presetRanges = [
  { label: 'Q1 2026', range: { start: '2026-01-01', end: '2026-03-31' } },
  // a () => { start, end } thunk is resolved fresh on render
  { label: 'Last 7 days', range: () => ({ start: iso(new Date(Date.now() - 6 * 864e5)), end: iso(new Date()) }) },
];
</script>

<template>
  <DatePicker v-model:value="date" min="2026-01-01" @change="onChange" />

  <!-- Custom header via the scoped #header slot -->
  <DatePicker v-model:value="date">
    <template #header="{ label, prev, next }">
      <div class="my-header">
        <button @click="prev">Prev</button>
        <strong>{{ label }}</strong>
        <button @click="next">Next</button>
      </div>
    </template>
  </DatePicker>

  <!-- Range selection with quick-pick presets + a #presets override -->
  <DatePicker
    selectionMode="range"
    v-model:value="range"
    :presetRanges="presetRanges"
    @rangeComplete="(e) => console.log('range:', e.value)"
  >
    <template #presets="{ presets, apply }">
      <button v-for="p in presets" :key="p.label" @click="apply(p.range)">{{ p.label }}</button>
    </template>
  </DatePicker>
</template>
svelte
<script lang="ts">
  import DatePicker from '@rozie-ui/date-picker-svelte';

  let date = $state(''); // ISO YYYY-MM-DD, '' = no selection

  // Range mode: value becomes a { start, end } object.
  let range = $state({ start: '', end: '' });
  const iso = (d) => d.toISOString().slice(0, 10);
  const presetRanges = [
    { label: 'Q1 2026', range: { start: '2026-01-01', end: '2026-03-31' } },
    { label: 'Last 7 days', range: () => ({ start: iso(new Date(Date.now() - 6 * 864e5)), end: iso(new Date()) }) },
  ];
</script>

<DatePicker
  bind:value={date}
  min="2026-01-01"
  onchange={(e) => console.log('picked:', e.value)}
/>

<!-- Custom header via the #header snippet -->
<DatePicker bind:value={date}>
  {#snippet header({ label, prev, next })}
    <div class="my-header">
      <button onclick={prev}>Prev</button>
      <strong>{label}</strong>
      <button onclick={next}>Next</button>
    </div>
  {/snippet}
</DatePicker>

<!-- Range selection. NOTE: Svelte LOWERCASES the event prop → onrangecomplete
     (NOT onRangeComplete — a camelCase binding silently never fires). -->
<DatePicker
  selectionMode="range"
  bind:value={range}
  {presetRanges}
  onrangecomplete={(e) => console.log('range:', e.value)}
>
  {#snippet presets({ presets, apply })}
    {#each presets as p (p.label)}
      <button onclick={() => apply(p.range)}>{p.label}</button>
    {/each}
  {/snippet}
</DatePicker>
ts
import { Component } from '@angular/core';
import { DatePicker } from '@rozie-ui/date-picker-angular';

@Component({
  selector: 'app-demo',
  standalone: true,
  imports: [DatePicker],
  template: `
    <DatePicker [(value)]="date" min="2026-01-01" (change)="onChange($event)" />

    <!-- Range selection with quick-pick presets -->
    <DatePicker
      selectionMode="range"
      [(value)]="range"
      [presetRanges]="presetRanges"
      (rangeComplete)="onRange($event)"
    />
  `,
})
export class DemoComponent {
  date = ''; // ISO YYYY-MM-DD, '' = no selection
  range: { start: string; end: string } = { start: '', end: '' };
  presetRanges = [
    { label: 'Q1 2026', range: { start: '2026-01-01', end: '2026-03-31' } },
    { label: 'Last 7 days', range: () => {
      const iso = (d: Date) => d.toISOString().slice(0, 10);
      return { start: iso(new Date(Date.now() - 6 * 864e5)), end: iso(new Date()) };
    } },
  ];
  onChange(e: { value: string }) {
    console.log('picked:', e.value);
  }
  onRange(e: { value: { start: string; end: string } }) {
    console.log('range:', e.value);
  }
}
tsx
import { createSignal } from 'solid-js';
import { DatePicker } from '@rozie-ui/date-picker-solid';

export function Demo() {
  const [date, setDate] = createSignal('');
  return (
    <DatePicker
      value={date()}
      onValueChange={setDate}
      min="2026-01-01"
      onChange={(e) => console.log('picked:', e.value)}
    />
  );
}

// Range selection with presets + a #presets override.
export function RangeDemo() {
  const [range, setRange] = createSignal({ start: '', end: '' });
  const iso = (d: Date) => d.toISOString().slice(0, 10);
  const presetRanges = [
    { label: 'Q1 2026', range: { start: '2026-01-01', end: '2026-03-31' } },
    { label: 'Last 7 days', range: () => ({ start: iso(new Date(Date.now() - 6 * 864e5)), end: iso(new Date()) }) },
  ];
  return (
    <DatePicker
      selectionMode="range"
      value={range()}
      onValueChange={setRange}
      presetRanges={presetRanges}
      onRangeComplete={(e) => console.log('range:', e.value)}
    >
      {{
        presets: ({ presets, apply }) => (
          <div class="my-presets">
            {presets.map((p) => (
              <button onClick={() => apply(p.range)}>{p.label}</button>
            ))}
          </div>
        ),
      }}
    </DatePicker>
  );
}
ts
import '@rozie-ui/date-picker-lit';

// <rozie-date-picker> is a custom element. Bind `value`/`min`/`max` as
// properties and listen for `value-change` (the two-way ISO date) + `change`.
const el = document.querySelector('rozie-date-picker');
el.min = '2026-01-01';
el.value = '';
el.addEventListener('value-change', (e) => {
  el.value = e.detail;
});
el.addEventListener('change', (e) => {
  console.log('picked:', e.detail.value);
});

// Range selection. The OBJECT value + the function-valued presets MUST be set
// via a PROPERTY, never a string attribute (value="..." would stringify to
// '[object Object]') — the SAME rule already in force for `disabledDates`.
el.selectionMode = 'range';
el.value = { start: '', end: '' };            // property binding (.value), not an attribute
el.presetRanges = [
  { label: 'Q1 2026', range: { start: '2026-01-01', end: '2026-03-31' } },
  { label: 'Last 7 days', range: () => ({ start: '2026-06-19', end: '2026-06-25' }) },
];
// The custom event name is CASE-PRESERVED on Lit → 'rangeComplete'.
el.addEventListener('rangeComplete', (e) => {
  console.log('range:', e.detail.value);
});

Imperative handle

Beyond props and events, DatePicker exposes imperative methods (declared once in the .rozie source via $expose). Grab a handle through your framework's native ref mechanism and call them directly:

tsx
import { useRef } from 'react';
import { DatePicker, type DatePickerHandle } from '@rozie-ui/date-picker-react';

const picker = useRef<DatePickerHandle>(null);
// <DatePicker ref={picker} ... />
picker.current?.focus();
picker.current?.goToToday();
picker.current?.clear();
vue
<script setup>
import { ref } from 'vue';
const picker = ref();          // template ref
</script>

<template>
  <DatePicker ref="picker" v-model:value="date" />
  <button @click="picker.goToToday()">Today</button>
</template>
svelte
<script>
  let picker;                  // component instance via bind:this
</script>

<DatePicker bind:this={picker} bind:value={date} />
<button onclick={() => picker.goToToday()}>Today</button>
ts
@Component({ /* ... */ })
export class DemoComponent {
  @ViewChild(DatePicker) picker!: DatePicker;   // or the viewChild() signal
  jumpToToday() { this.picker.goToToday(); }
  reset() { this.picker.clear(); }
}
tsx
import { DatePicker, type DatePickerHandle } from '@rozie-ui/date-picker-solid';

let handle: DatePickerHandle | undefined;
// The ref callback receives the HANDLE object (not the DOM node).
<DatePicker ref={(h) => (handle = h)} value={date()} />;
handle?.goToToday();
ts
// The custom element IS the handle — exposed methods are public element methods.
const el = document.querySelector('rozie-date-picker');
el.focus();
el.goToToday();
el.clear();

See also

Pre-v1.0 — internal monorepo.