<script setup lang="ts">
import { ALabel, ATimeFieldInput, ATimeFieldRoot } from 'akar';
</script>
<template>
<div class="flex flex-col gap-2">
<ALabel
class="text-sm"
for="birthday"
>
Birthday
</ALabel>
<ATimeFieldRoot
id="birthday"
v-slot="{ segments }"
class="group text-sm color-text-highlighted px-2.5 py-1.5 rounded-md bg-background inline-flex gap-0.5 select-none ring ring-ring-accented ring-inset transition-colors items-center relative focus-visible:(ring-2 ring-primary ring-inset)"
>
<template
v-for="item in segments"
:key="item.part"
>
<ATimeFieldInput
:part="item.part"
class="text-center outline-hidden rounded transition-colors-280 data-[placeholder]:color-text-dimmed data-[segment=literal]:color-text-muted focus:bg-background-elevated"
:class="{
'w-7': item.part !== 'literal',
}"
>
{{ item.value }}
</ATimeFieldInput>
</template>
</ATimeFieldRoot>
</div>
</template>
The component depends on the @internationalized/date package, which solves a lot of the problems that come with working with dates and times in JavaScript.
We highly recommend reading through the documentation for the package to get a solid feel for how it works, and you'll need to install it in your project to use the date-related components.
Install the date package.
pnpm add @internationalized/date
npm install @internationalized/date
bun add @internationalized/date
Import all parts and piece them together.
<script setup>
import {
ATimeFieldInput,
ATimeFieldRoot,
} from 'akar';
</script>
<template>
<ATimeFieldRoot>
<ATimeFieldInput />
</ATimeFieldRoot>
</template>
One benefit of using Akar is its flexibility and low-level control over the components. However, this also means that you may need to manually construct more complex UI elements by combining multiple Akar components together.
If you feel there's a lot of elements that needs to be constructed manually using Akar, consider using Pohon UI instead. It provides a higher-level abstraction over Akar components with pre-defined styles and behaviors that can help you build UIs faster.
Contains all the parts of a time field
| Prop | Default | Type |
|---|---|---|
as | 'div' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
defaultPlaceholder | TimeValueThe default placeholder date | |
defaultValue | TimeValueThe default value for the calendar | |
dir | 'ltr' | 'rtl'The reading direction of the time field when applicable. | |
disabled | false | booleanWhether or not the time field is disabled |
granularity | 'hour' | 'minute' | 'second'The granularity to use for formatting times. Defaults to minute if a Time is provided, otherwise defaults to minute. The field will render segments for each part of the date up to and including the specified granularity | |
hideTimeZone | booleanWhether or not to hide the time zone segment of the field | |
hourCycle | 12 | 24The hour cycle used for formatting times. Defaults to the local preference | |
id | stringId of the element | |
locale | stringThe locale to use for formatting dates | |
maxValue | TimeValueThe maximum date that can be selected | |
minValue | TimeValueThe minimum date that can be selected | |
modelValue | TimeValue | null | |
name | stringThe name of the field. Submitted with its owning form as part of a name/value pair. | |
placeholder | TimeValueThe placeholder date, which is used to determine what time to display when no time is selected. This updates as the user navigates the field | |
readonly | false | booleanWhether or not the time field is readonly |
required | booleanWhen | |
step | DateStepThe stepping interval for the time fields. Defaults to |
| Event | Type |
|---|---|
update:modelValue | [date: TimeValue]Event handler called whenever the model value changes |
update:placeholder | [date: TimeValue]Event handler called whenever the placeholder value changes |
| Slot | Type |
|---|---|
modelValue | TimeValue The controlled checked state of the field. Can be bound as |
segments | { part: SegmentPart; value: string; }[]The time field segment contents |
isInvalid | booleanValue if the input is invalid |
Contains the time field segments
| Prop | Default | Type |
|---|---|---|
as | 'div' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
part* | 'day' | 'month' | 'year' | 'hour' | 'minute' | 'second' | 'dayPeriod' | 'literal' | 'timeZoneName'The part of the date to render |
| Attribute | Value |
|---|---|
[data-disabled] | Present when disabled |
[data-invalid] | Present when invalid |
[data-placeholder] | Present when no value is set |
| Key | Description |
|---|---|
Tab | When focus moves onto the time field, focuses the first segment. |
ArrowLeftArrowRight | Navigates between the time field segments. |
ArrowUpArrowDown | Increments/changes the value of the segment. |
0-9 | When the focus is on a numeric |
Backspace | Deletes a digit from the focused numeric segments. |
AP | When the focus is on the day period, it sets it to AM or PM. |