Skip to content
EspañolEnglish
All components (244)

Week and day agenda

Dates and time · WeekAgenda · .amset-weekagenda

What it is and when to use it

The agenda of a week or a day: a grid of hours with appointments placed where they fall. Those that overlap go side by side; those that do not take the full width.

When to use it

  • Appointments, shifts, bookings: things with a start and end time within a day.
  • Appointments are dragged to another day or hour and stretched by the bottom edge. Everything snaps to the step (step, 15 min by default) and stays within the range shown (startHour to endHour).
  • The agenda saves nothing: it notifies through onEventChange and whoever uses it changes their appointments. If they do not, the appointment goes back to where it was.
  • readOnly leaves it view-only; an appointment with locked does not move even if the others do.
  • onSlotSelect reports the slot chosen (day and time), with a click or with the keyboard, to create an appointment; onEventPress the appointment pressed.

On a narrow screen (under 40 rem of its own width, or with layout="compact") the grid does not fit and becomes a list of days like the Teams mobile one: on top, fixed, the strip with the days of the week (and the whole month if expanded); below, the days with their appointments, scrolled downward. The strip follows the list (the week on top is that of the day going by at the top), pressing a day takes the list to it and "Today" goes back to today. There, appointments are pressed (onEventPress), not dragged.

Repeating appointments (repeat): an appointment with repeat unfolds by itself into one per date, with nothing to generate by whoever uses it. freq (daily, weekly, monthly, yearly), interval, weekdays (on weekly ones), until, count and except (dates on which it does not fall). It follows the iCalendar rules: count counts what the rule generates and the exceptions are removed afterwards, and a monthly one that falls on the 31st skips the months with fewer days. Each time carries the key series#date (parseOccurrenceKey reads it) and onEventChange also delivers series and occurrence: "only this time" or "the whole series" is decided by whoever uses it.

Time zones (timeZone): with the agenda's zone, an appointment written in another one (timeZone on the appointment) is drawn at the agenda's time, with the daylight saving of each date. If it crosses midnight in the agenda's zone it comes out split into one piece per day, locked. What is moved is delivered in the agenda's zone and onEventChange says so in timeZone.

Resources (resources): in the day view, one column per room or person; the appointment (resource) goes to its column, moves from one to another by dragging it or with Alt and the left and right arrows, and onEventChange and onSlotSelect deliver the resource. In the week view the split is still by days.

When not to

  • Seeing a whole month with its events: MonthAgenda. Choosing a free slot: SlotPicker.
  • Appointments that last several days, or "all day" events: it does not cover them. Those that cross midnight only come out split when it is the time zone that crosses them.

Keyboard: with onSlotSelect, Tab reaches the grid of slots first: the arrow keys move the slot cursor (one step at a time and one day at a time), Page Up and Page Down an hour at a time, Home and End go to the first and the last slot of the day, the day and time are announced, and Enter or Space choose the slot. After that, Tab walks the appointments. Alt and the arrows move the appointment (up and down, the time; left and right, the day); Alt, Shift and up or down change its length. Every change is announced.

Accessibility: each appointment carries its day and time in its name ("Meeting, Thursday 15 October, from 10:00 to 11:00"); the title on top is a live region that announces the change of week; the "now" line and the hours in the margin are decorative.

Fine-tuning: --amset-weekagenda-hour (height of an hour), -gutter (width of the hours column), -height (maximum height with a fixed header), -radius and -now (colour of the now line).

What it looks like

Oct 11 – 17, 2026

Alt and the arrow keys move the appointment; Alt, Shift and the up or down arrows change its length.

Sun11
Mon12
Tue13
Wed14
Thu15
Fri16
Sat17

<WeekAgenda
  label="Team agenda"
  events={citas}
  initialDay="2026-10-15"
  startHour={8}
  endHour={18}
  onEventChange={aplicar}
/>

Props

Import it with import { WeekAgenda } from '@amset/ui'. Required props are marked.

PropTypeWhat it does
eventsrequiredreadonly WeekAgendaEvent[]The appointments. One can carry `repeat` (it repeats), `timeZone` (its hours are from another zone) and `resource` (it takes a room or a person): the agenda unfolds, converts and splits by itself.
labelrequiredstringWhat the agenda is about. Required: it names the grid.
classNamestringMerged with the library classes; it does not replace them.
daystringA day of the week that is shown (`YYYY-MM-DD`), controlled from outside. By default, today.
endHournumberLast hour shown, not included (1 to 24). By default, 21.
firstDayOfWeekFirstDayOfWeek—
initialDaystring—
initialViewWeekAgendaView—
layoutWeekAgendaLayoutOn a narrow screen (under 40 rem of its own width) the grid does not fit: it becomes a list of days with the week strip on top, like the Teams mobile one. `auto` (the default) decides by itself; `full` or `compact` force it. In the list appointments are pressed (`onEventPress`) but not dragged.
onDayChange(iso: string) => void—
onEventChange(change: AgendaChange) => voidNotifies of an appointment that was moved or stretched, with the new day and times. The agenda does NOT change `events`.
onEventPress(key: string) => voidNotifies of the appointment pressed (click, Enter or Space). If it is dragged, it does not count as pressing it.
onRangeSelect(range: { readonly date: string; readonly start: string; readonly end: string; readonly resource?: string; }) => voidNotifies of the stretch chosen: the day and the start and end times, snapped to the step. It is chosen by dragging across the empty slots of a column, or with the keyboard by stretching the slot cursor with Shift and the up and down arrows, then Enter. A single click still goes to `onSlotSelect`. With `onRangeSelect` and without `onSlotSelect`, the grid also offers the slot cursor so the keyboard can choose.
onSlotSelect(slot: { readonly date: string; readonly start: string; readonly resource?: string; }) => voidNotifies of the slot chosen: the day and the time, snapped to the step. It is chosen with a click or with the keyboard: the grid receives focus, the arrow keys move the slot cursor (Page Up and Page Down an hour; Home and End, the first and the last of the day), the day and time are announced, and Enter or Space choose. Without this prop the grid offers no slots.
onViewChange(view: WeekAgendaView) => void—
readOnlybooleanWith `true`, appointments are not moved or stretched.
resourcesreadonly AgendaResource[]Splits the DAY view into one column per resource, and an appointment moves from one resource to another by dragging it or with Alt and the left and right arrows. Appointments without a resource, or of one that is not in the list, do not show in that view. The week view is still by days.
showWeekendsbooleanWith `false`, the week view does not paint Saturday or Sunday. By default, `true`.
startHournumberFirst hour shown (0 to 23). By default, 7.
stepnumberHow many minutes it snaps to when moving or stretching: 5, 10, 15, 30 or 60. By default, 15.
timeZonestringThe time zone (`Europe/Madrid`) in which the agenda's hours are read and written. An appointment with another `timeZone` is converted to this one, with the daylight saving of each date, and if it crosses midnight in it, it comes out split into one piece per day (locked). `onEventChange` delivers the hours in this zone and says so in `timeZone`. Without it, the hours are left as they come.
viewWeekAgendaViewThe view, controlled from outside: `week` or `day`.

It also accepts the attributes of the element it renders: className, style, data-*, aria-* and its events.

CSS variables

These CSS variables are how you adapt it. Declare them on the component's selector, not on :root: the stylesheet redeclares them in the rule itself, and a declaration on the same element always wins.

VariableDefault
--amset-weekagenda-hour3.5rem
--amset-weekagenda-gutter3.5rem
--amset-weekagenda-radiusvar(--amset-radius)
--amset-weekagenda-nowvar(--amset-error-solid)

How to change it

.amset-weekagenda {
  --amset-weekagenda-hour: ...;
  --amset-weekagenda-gutter: ...;
}

In the test bench

Every state and variant, to try one at a time, on its page at ui.amset.tech: