<CoarDayView> — Day View Preview
Single-day time-grid surface — one hour-axis on the left, one day column on the right. Multi-day all-day events that touch the visible day appear in the all-day band that pins under the day header. Use it standalone via useDayView() when you need just the day view without the <CoarCalendar> shell.
<CoarDayView :builder="builder" />Standalone usage
import { ref } from 'vue';
import { Temporal } from '@js-temporal/polyfill';
import {
CoarDayView,
useDayView,
type CalendarEvent,
} from '@cocoar/vue-calendar';
const events = ref<CalendarEvent[]>([
{
id: 'standup',
start: Temporal.ZonedDateTime.from('2026-04-15T09:00:00[UTC]'),
end: Temporal.ZonedDateTime.from('2026-04-15T09:15:00[UTC]'),
},
]);
const date = ref('2026-04-15');
const { builder, api } = useDayView();
builder
.events(events)
.date(date)
.timezone('UTC')
.timeRange([8, 18])
.slotDuration(15)
.onTimeClick(({ time }) => console.log(time.toString()));<CoarDayView :builder="builder" />The Day view shares its builder type, CalendarBuilder, with the Week view — they differ only in the days array the wrapper computes (Day uses [date], Week uses weekDates(date, fdow)).
<template>
<div style="height: 600px; border: 1px solid var(--coar-border-neutral-tertiary); border-radius: var(--coar-radius-xs); overflow: hidden;">
<CoarDayView :builder="builder" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import {
CoarDayView,
useDayView,
Temporal,
type CalendarEvent,
} from '@cocoar/vue-calendar';
const date = ref(Temporal.PlainDate.from('2026-04-15'));
const pd = (iso: string) => Temporal.PlainDate.from(iso);
const zdt = (iso: string, tz = 'Europe/Vienna') =>
Temporal.ZonedDateTime.from(`${iso}[${tz}]`);
const events = ref<CalendarEvent[]>([
// All-day band: a multi-day OOO that touches today.
{
id: 'devconf',
start: pd('2026-04-13'),
end: pd('2026-04-16'),
meta: { title: 'DevConf — Vienna', color: '#7c3aed' },
},
// Three timed events with a 3-deep overlap cluster.
{
id: 'standup',
start: zdt('2026-04-15T09:00:00'),
end: zdt('2026-04-15T09:30:00'),
meta: { title: 'Daily standup', color: '#10b981' },
},
{
id: 'design',
start: zdt('2026-04-15T11:00:00'),
end: zdt('2026-04-15T12:30:00'),
meta: { title: 'Design review', color: '#8b5cf6' },
},
{
id: 'pair',
start: zdt('2026-04-15T11:30:00'),
end: zdt('2026-04-15T13:00:00'),
meta: { title: 'Pair: calendar', color: '#f59e0b' },
},
{
id: 'lunch',
start: zdt('2026-04-15T12:00:00'),
end: zdt('2026-04-15T13:00:00'),
meta: { title: 'Lunch with Anna', color: '#ef4444' },
},
{
id: 'one-on-one',
start: zdt('2026-04-15T15:00:00'),
end: zdt('2026-04-15T15:45:00'),
meta: { title: '1:1 with Bernhard', color: '#3b82f6' },
},
]);
const { builder } = useDayView();
builder
.events(events)
.date(date)
.timezone('Europe/Vienna')
// Apply drag/keyboard moves in place so the demo is interactive.
.onEventDrop(({ event, next }) => {
const idx = events.value.findIndex((e) => e.id === event.id);
if (idx < 0) return;
events.value = [
...events.value.slice(0, idx),
{ ...event, start: next.start, ...(next.end ? { end: next.end } : {}) },
...events.value.slice(idx + 1),
];
});
</script>
Working hours
Constrain the visible hour range via timeRange([startHour, endHour]) and tighten drag-snap precision via slotDuration(15) for a 15-minute grid. Events outside the visible window are still in the data set but invisible.
Visible hour range constrained to [8, 18]; slot subdivision tightened to 15 min for finer drag-snap. The early flight (5–7 AM) is still in events but lives off the visible window.
<template>
<div>
<p class="hint">
Visible hour range constrained to <code>[8, 18]</code>; slot
subdivision tightened to 15 min for finer drag-snap. The early
flight (5–7 AM) is still in <code>events</code> but lives off
the visible window.
</p>
<div style="height: 520px; border: 1px solid var(--coar-border-neutral-tertiary); border-radius: var(--coar-radius-xs); overflow: hidden;">
<CoarDayView :builder="builder" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import {
CoarDayView,
useDayView,
Temporal,
type CalendarEvent,
} from '@cocoar/vue-calendar';
const date = ref(Temporal.PlainDate.from('2026-04-15'));
const zdt = (iso: string, tz = 'Europe/Vienna') =>
Temporal.ZonedDateTime.from(`${iso}[${tz}]`);
const events = ref<CalendarEvent[]>([
// Off-window early — invisible at timeRange [8, 18].
{
id: 'red-eye',
start: zdt('2026-04-15T05:00:00'),
end: zdt('2026-04-15T07:30:00'),
meta: { title: 'Early flight', color: '#84cc16' },
},
{
id: 'standup',
start: zdt('2026-04-15T09:00:00'),
end: zdt('2026-04-15T09:15:00'),
meta: { title: 'Daily standup', color: '#10b981' },
},
{
id: 'review',
start: zdt('2026-04-15T10:30:00'),
end: zdt('2026-04-15T11:30:00'),
meta: { title: 'Design review', color: '#8b5cf6' },
},
{
id: 'lunch',
start: zdt('2026-04-15T12:00:00'),
end: zdt('2026-04-15T13:00:00'),
meta: { title: 'Lunch', color: '#ef4444' },
},
{
id: 'deep-work',
start: zdt('2026-04-15T13:15:00'),
end: zdt('2026-04-15T16:45:00'),
meta: { title: 'Deep work', color: '#2563eb' },
},
]);
const { builder } = useDayView();
builder
.events(events)
.date(date)
.timezone('Europe/Vienna')
.timeRange({ startMinutes: 8 * 60, endMinutes: 18 * 60 })
.slotDuration(15)
.onEventDrop(({ event, next }) => {
const idx = events.value.findIndex((e) => e.id === event.id);
if (idx < 0) return;
events.value = [
...events.value.slice(0, idx),
{ ...event, start: next.start, ...(next.end ? { end: next.end } : {}) },
...events.value.slice(idx + 1),
];
});
</script>
<style scoped>
.hint {
margin: 0 0 12px;
font-size: 13px;
color: var(--coar-text-subtle, #6b7280);
}
.hint code {
font-family: var(--coar-font-family-mono, monospace);
font-size: 12px;
background: var(--coar-background-neutral-tertiary, #f3f4f6);
padding: 1px 5px;
border-radius: 3px;
}
</style>
Inside <CoarCalendar>
<CoarCalendar> and <CoarDayView> consume the SAME CalendarBuilder instance — there's no sub-builder forking. Time-grid config goes directly on the composer's builder:
const { builder } = useCalendar();
builder
.timeRange({ startMinutes: 8 * 60, endMinutes: 18 * 60 })
.slotDuration(15);When the active view is day or week, the same builder feeds the embedded <CoarTimeGrid>. View-specific settings have no effect outside their view.
useDayView<TMeta>()
function useDayView<TMeta>(): {
builder: CalendarBuilder<TMeta>;
api: CalendarApi<TMeta>;
};Returns a fresh standalone builder + its imperative api. The builder type is the same CalendarBuilder used by <CoarCalendar> — useDayView() is a thin shorthand that pre-sets view: 'day'.
Builder setters
Full reference: see the composer's API reference. Highlights for the day view:
| Setter | Argument | Default | Notes |
|---|---|---|---|
timeRange(r) | MaybeRefOrGetter<{ startMinutes, endMinutes }> | {0, 1440} | Visible hour range, in minutes from midnight. Events outside are still rendered into the all-day band when applicable. |
slotDuration(d) | MaybeRefOrGetter<number> | 30 | Slot subdivision (minutes). Also the snap step when dragging. |
pixelsPerHour(p) | MaybeRefOrGetter<number> | 60 | Vertical density. 60 = 30 px per 30-min slot. |
eventRenderer(r) | EventRenderer<TMeta> | — | Universal renderer. Branch on ctx.layout?.kind === 'positioned' (timed cards) vs 'allDayBar' (all-day band). |
dayHeaderRenderer(r) | DayHeaderRenderer | — | Per-day column header. |
Imperative API
interface CalendarApi<TMeta> {
goTo(date: Temporal.PlainDate): void;
goToToday(): void;
next(): void; // ±1 day in day-view
prev(): void;
getVisibleRange(): ViewWindow | null;
getVisibleEvents(): CalendarEvent<TMeta>[];
scrollToTime(time: Temporal.PlainTime): void; // Day / Week only
scrollToDate(date: Temporal.PlainDate): void; // Agenda only
refresh(): void;
refreshRange(window: ViewWindow): void;
readonly loading: Readonly<Ref<boolean>>;
readonly visibleRange: Readonly<Ref<ViewWindow | null>>;
readonly gridReady: Readonly<Ref<boolean>>;
}<CoarDayView> props + slots
| Prop | Type | Description |
|---|---|---|
builder | CalendarBuilder | Required. From useDayView() (or share the one from useCalendar()). |
| Slot | Scope | Purpose |
|---|---|---|
event | { event, layout } | Per-event renderer. layout is the PositionedEvent (lane / startMinutes / endMinutes / clipping flags). |
allDayEvent | { event, layout } | All-day band renderer. layout is the AllDayBar (lane / startCol / endCol / clipping flags). |
dayHeader | { date, isToday, isWeekend } | Per-day column header. |