| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
Value: 2026-09-04
<script setup lang="ts">
import { ref } from 'vue'
import { Calendar, Stack, Text } from '@hina-ui/vue'
const date = ref<string | null>('2026-09-04')
</script>
<template>
<Stack gap="sm" align="start">
<Calendar v-model="date" />
<Text tone="muted" size="sm">Value: {{ date ?? 'empty' }}</Text>
</Stack>
</template>
Usage
import { Calendar } from '@hina-ui/vue'
The calendar shows one month as a grid and a click picks a day. v-model binds an ISO 8601 string in the YYYY-MM-DD form, the same shape as DateField. The heading, weekday names and the first day of the week follow the current locale. The grid always shows six weeks, so paging never changes its height.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
Value: empty
<script setup lang="ts">
import { ref } from 'vue'
import { Calendar, Stack, Text } from '@hina-ui/vue'
const date = ref<string | null>(null)
</script>
<template>
<Stack gap="sm" align="start">
<Calendar v-model="date" placeholder="2026-09-01" />
<Text tone="muted" size="sm">Value: {{ date ?? 'empty' }}</Text>
</Stack>
</template>
Examples
Range
min and max bound the selectable range; days outside it are disabled and the paging buttons stop at the boundary months.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
<script setup lang="ts">
import { ref } from 'vue'
import { Calendar } from '@hina-ui/vue'
const date = ref<string | null>('2026-09-10')
</script>
<template>
<Calendar v-model="date" min="2026-09-07" max="2026-09-25" />
</template>
First day of the week and weekday format
weekStartsOn sets the first day of the week from 0 to 6, where 0 is Sunday, defaulting to the locale. weekdayFormat picks the weekday names: narrow is a single letter, short an abbreviation.
| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
|---|---|---|---|---|---|---|
31 | 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
<script setup lang="ts">
import { ref } from 'vue'
import { Calendar } from '@hina-ui/vue'
const date = ref<string | null>('2026-09-04')
</script>
<template>
<Calendar v-model="date" :week-starts-on="1" weekday-format="short" />
</template>
Sizes
size has three steps, sm, md and lg; each day cell is as tall as the control of the same step, and the paging buttons and heading follow.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
<script setup lang="ts">
import { Calendar, Stack } from '@hina-ui/vue'
</script>
<template>
<Stack gap="lg" align="start">
<Calendar size="sm" model-value="2026-09-04" />
<Calendar size="md" model-value="2026-09-04" />
<Calendar size="lg" model-value="2026-09-04" />
</Stack>
</template>
States
readonly keeps the calendar browsable by keyboard but not selectable; disabled disables it entirely.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
<script setup lang="ts">
import { Calendar, Inline } from '@hina-ui/vue'
</script>
<template>
<Inline gap="lg" align="start">
<Calendar model-value="2026-09-04" readonly />
<Calendar model-value="2026-09-04" disabled />
</Inline>
</template>
Behavior
- A click picks the day; clicking the picked day again does not clear it.
- The arrow keys move focus by day and by week, Home and End jump to the ends of the week, PageUp and PageDown page by month, and Enter or Space picks the focused day.
- Moving focus out of the month pages automatically.
- Clicking the heading opens the month view, and clicking the year there opens the year view, twelve years at a time; picking a year returns to the month view, picking a month returns to the day view on that month, and Esc steps back one level. All three views share the same width and height, so switching never jumps.
placeholdersets the month shown, the current month by default; after paging or switching views a date inside the new view is emitted asupdate:placeholder, sov-model:placeholdertracks or controls the shown month.
Accessibility
- The root carries the name from the locale plus the visible month, the grid is
role="grid"and every day is a button named with its full date. - Focus roves between days through a single tab stop; the focus ring appears only for keyboard use.
- The paging buttons carry names from the locale.
API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | string | null | null | The picked day, YYYY-MM-DD |
placeholder | string | current month | The month shown, supports v-model:placeholder |
min | string | — | Lower bound of the selectable range |
max | string | — | Upper bound of the selectable range |
unavailable | (date: string) => boolean | — | Whether a given day cannot be picked |
weekStartsOn | 0 | 1 | 2 | 3 | 4 | 5 | 6 | locale | First day of the week |
weekdayFormat | 'narrow' | 'short' | 'narrow' | Format of the weekday names |
fixedWeeks | boolean | true | Whether six weeks are always shown |
readonly | boolean | false | Whether the calendar is read only |
disabled | boolean | false | Whether the calendar is disabled |
class | string | — | Classes appended to the root element |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue | value: string | null | The pick changed |
update:placeholder | value: string | The shown month changed, with a date inside the new view |