WeekPicker
Pick a whole week from a calendar.
SourcePackage @kerf-js/veneer
Preview
tsx
import { state } from '@kerf-js/core'import { Stack, Text, WeekPicker } from '@kerf-js/veneer'import type { IsoDate, IsoWeek } from '@kerf-js/veneer'export function Sprint() { const week = state<IsoWeek | null>('2026-W45') return ( <Stack gap="related"> <WeekPicker label="Sprint week" today={TODAY} value={week} /> <Text subtle role="caption" > Saved as {week.value ?? 'nothing'} </Text> </Stack> )}const TODAY: IsoDate = '2026-11-02'Installation
npm install @kerf-js/veneerUsage
tsx
import { WeekPicker } from '@kerf-js/veneer'Local week numbers
numbering="locale" follows the local first day of the week.
tsx
import { WeekPicker } from '@kerf-js/veneer'import type { IsoDate } from '@kerf-js/veneer'export function Locale() { return ( <WeekPicker label="Payroll week" today={TODAY} defaultValue="2026-W45" numbering="locale" /> )}const TODAY: IsoDate = '2026-11-02'Hint, error, read-only, disabled
The same hint, error, readonly and disabled as every field.
tsx
import { Grid, WeekPicker } from '@kerf-js/veneer'import type { IsoDate } from '@kerf-js/veneer'import { Stack, Text } from '@kerf-js/veneer'export function States() { return ( <Grid cols={2} gap="group" > <Cell name="Empty"> <WeekPicker label="Week" today={TODAY} /> </Cell> <Cell name="Hint"> <WeekPicker label="Week" today={TODAY} hint="Monday to Sunday." /> </Cell> <Cell name="Invalid"> <WeekPicker label="Week" today={TODAY} error="Choose the week you worked." /> </Cell> <Cell name="Read-only"> <WeekPicker label="Week" today={TODAY} defaultValue="2026-W44" readonly /> </Cell> <Cell name="Disabled"> <WeekPicker label="Week" today={TODAY} defaultValue="2026-W44" disabled /> </Cell> </Grid> )}const Cell = ({ name, children,}: { name: string children?: unknown}) => ( <Stack gap="tight"> <Text role="caption" subtle > {name} </Text> {children} </Stack>)const TODAY: IsoDate = '2026-11-02'A timesheet
The week gives the dates of its days. An ISO week starts on the Monday.
tsx
import { state } from '@kerf-js/core'import { Row, Stack, Text, WeekPicker} from '@kerf-js/veneer'import type { IsoDate, IsoWeek } from '@kerf-js/veneer'export function Timesheet() { const week = state<IsoWeek | null>('2026-W44') const day = (i: number) => new Date( mondayOf(week.value!).getTime() + i * 86400000, ) .toISOString() .slice(5, 10) return ( <Stack gap="group"> <WeekPicker label="Timesheet week" today={TODAY} value={week} /> {week.value ? ( <Stack gap="tight" divided > {DAYS.map((d, i) => ( <Row key={d} justify="between" > <Text> {d} {day(i)} </Text> <Text subtle>{HOURS[i]} h</Text> </Row> ))} <Row justify="between"> <Text role="label">Total</Text> <Text role="label"> {HOURS.reduce((a, b) => a + b, 0)} h </Text> </Row> </Stack> ) : ( <Text subtle> Pick a week to fill in its hours. </Text> )} </Stack> )}const TODAY: IsoDate = '2026-11-02'function mondayOf(week: string) { const [year, n] = [+week.slice(0, 4), +week.slice(6)] const jan4 = new Date(Date.UTC(year, 0, 4)) return new Date( jan4.getTime() + ((n - 1) * 7 - ((jan4.getUTCDay() + 6) % 7)) * 86400000, )}const DAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']const HOURS = [7.5, 8, 6, 8.5, 4]When to use
Use it for
- Timesheets, sprints and rotas that run by the week
Reach for something else
- DateRangeField, when the span can be any length
Accessibility
- Arrows
- Move through the days
- EnterorSpace
- Picks that day's week
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | The accessible name, drawn as the floating border label (or above, classic). Required. |
hint | unknown | — | One line of help under the control. |
error | unknown | — | Shown instead of the hint; marks the field invalid. |
icon | IconRef | — | Leading icon: it sweeps with the border. |
prefix | unknown | — | Text or an element inside the field before the value, such as $. |
suffix | unknown | — | Text or an element inside the field after the value, such as kg. |
variant | "floating" | "classic" | — | floating (default, or the app's veneer({ fields })) · classic: the label above. |
appearance | "line" | — | line: only a bottom line under the value, no box or fill. The boxed field otherwise. |
size | "sm" | "md" | "lg" | 'md' | Control size. md by default. |
clearable | boolean | false | A clear button (shown once there is a value). |
counter | number | — | Maximum length, shown as a counter. |
id | string | — | The element id. One is made for you if you leave it out. |
disabled | boolean | false | Turns it off, and takes it out of the tab order. |
readonly | boolean | false | Shows the value and lets it be selected and copied, but not changed. |
required | boolean | false | The form will not submit without it. |
name | string | — | The name it posts under in a form. |
locale | string | — | The language and region used to format values. |
today | string | — | Pins "today" (server render, tests); the browser's clock otherwise. |
presentation | Presentation | — | auto opens a popover, or a sheet when the viewport is under 600px wide; popover and sheet force one. |
value | `${number}-W${number}` | State<`${number}-W${number}` | null> | null | — | The current value, when you own the state. |
defaultValue | `${number}-W${number}` | null | — | The starting value, when the component owns the state. |
open | boolean | State<boolean> | — | A state box that holds whether it is open. |
defaultOpen | boolean | false | Starts open, when the component keeps its own open state. |
numbering | "iso" | "locale" | 'iso' | The day each grid row starts on: iso (the default) starts on Monday, so a row is one ISO 8601 week; locale starts on the locale's first day of the week. The value is an ISO week either way. |
| Event | Type | Default | Description |
|---|---|---|---|
onInput | ((e: InputEvent & { currentTarget: HTMLInputElement & HTMLTextAreaElemen… | — | Called on each keystroke. |
onValueChange | ((v: `${number}-W${number}` | null, reason: ChangeReason) => void) | — | Called with each new value, and whether a pointer, a key or code made the change. |
onOpenChange | ((o: boolean) => void) | — | Called with true when it opens and false when it closes. |
RelatedMonth pickerPeriod picker