Calendar
There are two calendars, drawn from the same days and keys.
ds-calendardraws a month the way a list draws its items: seven days across, a week to a row, each day a hairline box four squares wide and four high. Its date stands on the first square, two lines of events below it and one square to spare. Withcompact, a day is one square and the month becomes the small one, one of twelve in a year. Withpicker, it is a field that opens that small month to choose a date: see the picker.ds-calendar-largedraws months side by side as squares: a week to a column and the seven days down it, one and a half times the grid, in a rounded frame that scrolls sideways. A day on which something happens is filled with its colour, so a long piece of work reads as a band across the weeks.
Design examples
Section titled “Design examples”A compact fixed calendar puts day numbers on the small square grid.
<section class="specimen">
<ds-calendar compact fixed selectable value="2026-10-14"></ds-calendar><ds-row class="line" ><ds-text literal tone="muted" size="small">Field visit: 14 October</ds-text></ds-row>
</section>
<style>
.specimen { width: 100%; min-width: 0; --cell: calc(20px * var(--sf, 1)); }
.specimen .line { width: 100%; }
.specimen .grow { flex: 1; min-width: 0; }
.specimen .muted { color: var(--ds-text-color-muted); }
.specimen .mono { --ds-typeface-regular: var(--ds-typeface-mono); font-variant-numeric: tabular-nums; }
.specimen .value { width: calc(4 * var(--cell)); text-align: right; }
.specimen .mark { display: inline-flex; align-items: flex-end; width: var(--cell); height: var(--ds-control-height); flex: 0 0 var(--cell); }
.specimen .columns { display: flex; flex-wrap: wrap; gap: var(--cell); }
.specimen .columns > * { min-width: 0; }
.specimen fieldset { border: 0; padding: 0; margin: 0; }
.specimen legend { padding: 0; }
.specimen label { display: flex; align-items: flex-end; gap: calc(var(--cell) / 2); min-height: var(--cell); }
.specimen ds-panel { height: calc(10 * var(--cell)); }
</style> Two months lit by how much was written each day, as a contribution graph.
<section class="specimen">
<div class="columns"><ds-calendar compact heat fixed no-today month="2026-06" label="Writing, June 2026" literal data-showcase-props="{"events": [{"title": "1 pages", "start": "2026-06-01", "count": 1}, {"title": "3 pages", "start": "2026-06-03", "count": 3}, {"title": "2 pages", "start": "2026-06-04", "count": 2}, {"title": "4 pages", "start": "2026-06-08", "count": 4}, {"title": "6 pages", "start": "2026-06-09", "count": 6}, {"title": "2 pages", "start": "2026-06-10", "count": 2}, {"title": "5 pages", "start": "2026-06-12", "count": 5}, {"title": "2 pages", "start": "2026-06-15", "count": 2}, {"title": "7 pages", "start": "2026-06-16", "count": 7}, {"title": "9 pages", "start": "2026-06-17", "count": 9}, {"title": "3 pages", "start": "2026-06-18", "count": 3}, {"title": "1 pages", "start": "2026-06-19", "count": 1}, {"title": "4 pages", "start": "2026-06-22", "count": 4}, {"title": "8 pages", "start": "2026-06-23", "count": 8}, {"title": "12 pages", "start": "2026-06-24", "count": 12}, {"title": "6 pages", "start": "2026-06-25", "count": 6}, {"title": "2 pages", "start": "2026-06-26", "count": 2}, {"title": "3 pages", "start": "2026-06-29", "count": 3}, {"title": "5 pages", "start": "2026-06-30", "count": 5}]}"></ds-calendar><ds-calendar compact heat fixed no-today month="2026-07" label="Writing, July 2026" literal data-showcase-props="{"events": [{"title": "2 pages", "start": "2026-07-01", "count": 2}, {"title": "6 pages", "start": "2026-07-02", "count": 6}, {"title": "1 pages", "start": "2026-07-04", "count": 1}, {"title": "3 pages", "start": "2026-07-07", "count": 3}, {"title": "9 pages", "start": "2026-07-08", "count": 9}, {"title": "4 pages", "start": "2026-07-09", "count": 4}, {"title": "1 pages", "start": "2026-07-11", "count": 1}, {"title": "7 pages", "start": "2026-07-12", "count": 7}, {"title": "10 pages", "start": "2026-07-13", "count": 10}, {"title": "2 pages", "start": "2026-07-14", "count": 2}, {"title": "5 pages", "start": "2026-07-17", "count": 5}, {"title": "3 pages", "start": "2026-07-18", "count": 3}, {"title": "11 pages", "start": "2026-07-19", "count": 11}, {"title": "1 pages", "start": "2026-07-20", "count": 1}, {"title": "2 pages", "start": "2026-07-23", "count": 2}, {"title": "8 pages", "start": "2026-07-24", "count": 8}, {"title": "6 pages", "start": "2026-07-25", "count": 6}, {"title": "4 pages", "start": "2026-07-26", "count": 4}, {"title": "1 pages", "start": "2026-07-29", "count": 1}, {"title": "3 pages", "start": "2026-07-30", "count": 3}, {"title": "9 pages", "start": "2026-07-31", "count": 9}]}"></ds-calendar></div><ds-row class="line" ><ds-text literal tone="muted" size="small">Pages written each day: the busier the day, the stronger it is lit.</ds-text></ds-row>
</section>
<style>
.specimen { width: 100%; min-width: 0; --cell: calc(20px * var(--sf, 1)); }
.specimen .line { width: 100%; }
.specimen .grow { flex: 1; min-width: 0; }
.specimen .muted { color: var(--ds-text-color-muted); }
.specimen .mono { --ds-typeface-regular: var(--ds-typeface-mono); font-variant-numeric: tabular-nums; }
.specimen .value { width: calc(4 * var(--cell)); text-align: right; }
.specimen .mark { display: inline-flex; align-items: flex-end; width: var(--cell); height: var(--ds-control-height); flex: 0 0 var(--cell); }
.specimen .columns { display: flex; flex-wrap: wrap; gap: var(--cell); }
.specimen .columns > * { min-width: 0; }
.specimen fieldset { border: 0; padding: 0; margin: 0; }
.specimen legend { padding: 0; }
.specimen label { display: flex; align-items: flex-end; gap: calc(var(--cell) / 2); min-height: var(--cell); }
.specimen ds-panel { height: calc(10 * var(--cell)); }
</style> (function mountShowcase(root) {
root.querySelectorAll("[data-showcase-props]").forEach((element) => {
const props = JSON.parse(element.dataset.showcaseProps);
Object.assign(element, props);
if (element.localName === "ds-sidebar") {
let items = props.items;
const render = () => {
let collapsedDepth;
const visible = items.filter((item) => {
const depth = item.depth ?? 0;
if (collapsedDepth !== void 0 && depth > collapsedDepth) return false;
collapsedDepth = item.expanded === false ? depth : void 0;
return true;
});
Object.assign(element, { items: visible });
};
element.addEventListener("sidebar-activate", (event) => {
const id = event.detail.id;
items = items.map((item) => ({ ...item, current: item.id === id }));
render();
});
element.addEventListener("sidebar-toggle", (event) => {
const { id, expanded } = event.detail;
items = items.map((item) => item.id === id ? { ...item, expanded } : item);
render();
});
}
});
root.querySelectorAll("ds-token-field").forEach((field) => {
field.addEventListener("ds-token-commit", (event) => {
const { text } = event.detail;
const input = field.querySelector("input");
if (!input || !text.trim()) return;
const token = document.createElement("ds-token");
token.setAttribute("value", text.trim());
token.setAttribute("label", text.trim());
token.setAttribute("remove-label", `Remove ${text.trim()}`);
field.insertBefore(token, input);
input.value = "";
input.dispatchEvent(new Event("input", { bubbles: true }));
});
field.addEventListener("ds-token-remove", (event) => {
const token = event.target;
if (token instanceof Element && token.localName === "ds-token") token.remove();
});
});
window.addEventListener("message", (event) => {
if (event.origin !== location.origin || event.source !== parent || event.data?.type !== "ds1-example-theme") return;
requestAnimationFrame(() => root.querySelectorAll("ds-chart, ds-spark, ds-bars").forEach((chart) => {
chart.refreshTheme?.();
}));
});
})(document); One picker chooses the stay: arrival and departure in the same month, written as one value.
<section class="specimen">
<ds-calendar picker label="Arrival and departure" literal name="stay" value="2026-11-04/2026-11-07"></ds-calendar>
</section>
<style>
.specimen { width: 100%; min-width: 0; --cell: calc(20px * var(--sf, 1)); }
.specimen .line { width: 100%; }
.specimen .grow { flex: 1; min-width: 0; }
.specimen .muted { color: var(--ds-text-color-muted); }
.specimen .mono { --ds-typeface-regular: var(--ds-typeface-mono); font-variant-numeric: tabular-nums; }
.specimen .value { width: calc(4 * var(--cell)); text-align: right; }
.specimen .mark { display: inline-flex; align-items: flex-end; width: var(--cell); height: var(--ds-control-height); flex: 0 0 var(--cell); }
.specimen .columns { display: flex; flex-wrap: wrap; gap: var(--cell); }
.specimen .columns > * { min-width: 0; }
.specimen fieldset { border: 0; padding: 0; margin: 0; }
.specimen legend { padding: 0; }
.specimen label { display: flex; align-items: flex-end; gap: calc(var(--cell) / 2); min-height: var(--cell); }
.specimen ds-panel { height: calc(10 * var(--cell)); }
</style> Try it
Section titled “Try it”Press a day to select it, or move with the arrow keys and Page Up and Page Down. The third event on a day folds into +2; press it to unfold them.
<ds-calendar selectable week-numbers></ds-calendar> const calendar = document.querySelector('ds-calendar');
calendar.events = [
{ title: 'Design review', start: '2026-10-03', time: '10:00', color: 'var(--ds-zenith-blue)' },
{ title: 'Launch', start: '2026-10-12', end: '2026-10-14', color: 'var(--ds-apple-green)' },
{ title: 'Dentist', start: '2026-10-12', time: '08:30' },
{ title: 'Dinner', start: '2026-10-12', time: '19:00', color: 'var(--ds-pink)' },
];
calendar.addEventListener('change', event => console.log(event.detail.value)); compact draws a month one square a day, as a year of months is drawn. With events, the days that have one keep the ink.
<ds-calendar compact selectable fixed></ds-calendar> heat lights each day by how much happens on it: the events’ counts added up, in four steps of the busiest day. Quiet days stay plain.
<ds-calendar compact heat fixed outside-days day-width="2"></ds-calendar> const calendar = document.querySelector('ds-calendar');
const month = calendar.shownMonth.slice(0, 7);
const counts = [0, 2, 5, 1, 0, 0, 3, 8, 4, 0, 1, 6, 12, 2, 0, 0, 7, 3, 9, 1, 0, 0, 2, 10, 5, 4, 0, 0, 1, 3, 6];
calendar.events = counts.flatMap((count, index) => count ? [{ title: count + ' changes', start: month + '-' + String(index + 1).padStart(2, '0'), count }] : []); Press a day to choose it; press another to end a range from it, and the pointer previews the end. The press after starts again. Each press fires change.
<ds-calendar compact selectable fixed outside-days day-width="2"></ds-calendar> Open it with a click, Enter or the down arrow. Press a first day and a last; press one day twice, or leave, for a single day. Escape closes it.
<div style="display:flex;flex-wrap:wrap;gap:var(--ds-unit)">
<ds-calendar picker label="When" literal name="when"></ds-calendar>
<ds-calendar picker label="Trip" literal name="trip" value="2026-10-21/2026-10-24"></ds-calendar>
</div> Weeks run sideways and the days down them. Scroll, or use the arrows and Today; a day several things share is split into bands.
<ds-calendar-large months="6" selectable></ds-calendar-large> const calendar = document.querySelector('ds-calendar-large');
calendar.events = [
{ title: 'Identity', start: '2026-09-08', end: '2026-10-06', color: 'var(--ds-zenith-blue)' },
{ title: 'Website', start: '2026-10-02', end: '2026-11-13', color: 'var(--ds-apple-green)' },
{ title: 'Campaign', start: '2026-11-09', end: '2026-12-04', color: 'var(--ds-pink)' },
]; A month
Section titled “A month”<ds-calendar month="2026-10" selectable week-numbers></ds-calendar>const calendar = document.querySelector("ds-calendar");calendar.events = [ { title: "Design review", start: "2026-10-03", time: "10:00", color: "var(--ds-zenith-blue)" }, { title: "Launch", start: "2026-10-12", end: "2026-10-14", color: "var(--ds-apple-green)" },];calendar.addEventListener("change", event => console.log(event.detail.value));| Measure | Size |
|---|---|
| A day | Four squares wide (day-width), its date’s square, lines squares of events (two), and one square to spare. |
| The title and arrows | One square, one square above the days. The title is a plain button, its words alone with no chevron, one control high, filled by the pointer 4px past its words at each side (see months and years). Today and the arrows stand at the end: each arrow a chevron on a square of its own, one control high, in the title grey until the pointer fills it. |
| The weekday names | One square, in the title grey, at the start of each day. |
| A date | At the end of its first square, in the title grey, tabular figures. |
| Today | A disc nine tenths of a square across, in red for blood, the date in white. |
| The selected day | A square of the same size with the system’s 4px corners, in Sharp blue, the date in white. |
| A range | Each end drawn as the selected day, the days between on a band of the blue at 16%. In a compact month the band is the marks’ height on their line, from the middle of the first day to the middle of the last, so the ends and the band read as one bar. |
| An event | One square, drawn one pixel short, its words 4px from its edges; the time first, fainter. Filled with its color or the fill. |
| More events than lines | The last line says +2; pressing it lays the day’s events over the days below. |
| A week number | W42 in the compressed face, at the start of the week’s first day, with week-numbers. |
| Lines | 1px in the line colour, centred on the grid lines. |
A day outside the month is an empty box. fixed always draws six weeks, so moving between months never changes the calendar’s height.
Compact
Section titled “Compact”compact makes every day a square, one square across by default: the date centred in it, the weekday names a letter each, the month’s name shortened, and no events written out. With day-width="2" each day is two squares each way, the weekday names take two letters, Today stands beside the arrows and the marks grow to a square and two thirds, for a month with more room. outside-days writes the days of the months before and after in the title grey; pressing one goes there. When the calendar has events, a day with one keeps the ink and a day without falls back to the title grey, so a year of small months shows where things happened.
<ds-calendar compact heat fixed></ds-calendar>calendar.events = [ { title: "3 changes", start: "2026-07-08", count: 3 }, { title: "12 changes", start: "2026-07-09", count: 12 },];heat lights each day by how much happens on it, as a contribution graph does. A day’s amount is its events’ counts added up (an event without one counts once, an event over several days counts on each). The busiest day of the month shown sets the scale, and every other day takes one of four steps of it: up to a quarter, a half, three quarters, or more. heat-max fixes the amount that lights a day fully, so months stay comparable. A day with nothing stays plain, and when the month has events at all its date falls back to the title grey; the neighbouring months’ days are never lit.
| Step | Light paper | Dark paper | The date |
|---|---|---|---|
| 1 | The accent’s pastel | Its dim | The ink; white on dark paper |
| 2 | Halfway to the accent | Halfway to the accent’s dark version | The ink; white on dark paper |
| 3 | The accent (Apple green) | The accent’s dark version | The ink |
| 4 | The accent deepened with 40% of the ink | The full accent | The ink |
The fill is the date’s mark, the same size as today’s disc and the selected square, with a picture’s corners, so it stays inside the day’s square and the grid; in a compact month the marks stand a pixel apart, as a contribution graph’s squares do. Every step keeps its date at 4.5:1 or more. Today and the selection draw over the heat. The fills are the palette’s tokens (--one-apple-green-pastel, --one-apple-green), each light-dark(); a page lights the month in another colour by setting --ds-calendar-heat-1 … -4 and their --ds-calendar-heat-ink-1 … -4 from the palette.
Months in squares
Section titled “Months in squares”<ds-calendar-large start="2026-09" months="6"></ds-calendar-large>| Measure | Size |
|---|---|
| A day | One square times scale (one and a half: 30px). |
| Lines | 1px times the scale, inside a frame whose corners are four tenths of a day. |
| Words | The heading size times the scale (19.5px). |
| The weekday names | Down the start, outside the scroll, every other one named; a letter each on a narrow screen. |
| The months | Each name over the week holding its first day; January and the first month carry the year. |
| A date | Written only on today, the selected day, and where an event starts or ends. |
| Today | A disc nine tenths of a day across in red for blood; the selected day a square of the ink. |
| A filled day | The event’s color, Apple green by default; days two or more events share are split into equal bands. |
The title names the month at the start of the view as it scrolls. The arrows move a month at a time and Today scrolls to today’s month; past the months drawn, start moves with them and navigate says so.
Choosing a day or a range
Section titled “Choosing a day or a range”<ds-calendar compact selectable day-width="2" value="2026-10-14/2026-10-20"></ds-calendar>There is one way to choose, in a month and in the picker: a person picks one day or a range in the same calendar, with nothing to switch. The first press chooses a day, and value is that day. The next press ends a range from it, before or after, and value becomes start/end (ISO 8601’s interval); pressing the same day again keeps the one day. The press after that starts again. While the end is still to come, the day under the pointer previews it.
change fires with each press that chooses: { value, previous, start, end }, end empty while it is still to come and the last day once it is chosen. A value set by the page is whole, so the next press starts again.
A selectable calendar shows Clear while something is chosen: a secondary button one control high, in the shared word, centred on the square right under the dates. With nothing chosen it is not there. It empties the value and fires change with value empty (start and end too). clear() does the same from code, in a month and in a picker (where it also closes the panel). required leaves Clear out; the picker’s month uses the picker’s own Clear.
Months and years
Section titled “Months and years”Pressing the title travels by months and years, as a date picker’s title does. The days go up to the twelve months of their year (the title reads the year and the arrows step a year), the year goes up to twelve years (the title reads them, 2016 – 2027, and the arrows step twelve). Choosing a year shows its months; choosing a month shows its days and fires navigate. Nothing is chosen on the way.
| Measure | Size |
|---|---|
| A month or a year | One square high and whole squares wide, three across a narrow month (two squares each) and four across a wider one, rows one square apart. |
| Its mark | Nine tenths of a square high with a picture’s corners: the chosen month or year in Sharp blue, today’s in the today red, the pointer’s in the fill. |
| The area | The days’ height, so nothing below moves between levels; the level a person moves to fades in (opacity and scale, none with reduced motion). |
The months and years are a grid with one Tab stop: the arrow keys move (past December is the next year’s January), Enter or Space chooses, and Escape goes back down a level without closing a picker. Month names and years come from the current language through format.ts. no-header leaves the travel out with the title.
Picker
Section titled “Picker”<form> <ds-calendar picker name="when" label="When" literal min="2026-10-01"></ds-calendar></form>picker.addEventListener("change", event => { console.log(event.detail.value); // "2026-10-21", "2026-10-21/2026-10-24", "2026-10-21T09:00/2026-10-21T10:00", or "" when cleared});With picker, the calendar is a field one control high, its value written in it and a chevron (chevron-down) at its end. A range is one picker and one value (Oct 21 – 24, 2026), never two pickers side by side for its ends. Pressing it opens a panel half a square below, on the menu’s frame: the first and last day written out where they can be typed, the compact month one square a day, an Include time switch and Clear.
It chooses as a month does. Each opening starts a new choice: the first day pressed is the value; the second, before or after, ends a range and closes the panel. Pressing the same day twice, or leaving after the first press, keeps one day.
The value is ISO 8601: a day, a day with its time, or two of them joined by a slash, which is also what a form sends. A value with a time turns Include time on; time sets it from the page.
| Value | Face |
|---|---|
2026-10-21 | Oct 21, 2026 |
2026-10-21/2026-10-24 | Oct 21 – 24, 2026 |
2026-10-21T09:00/2026-10-21T10:00 | Oct 21, 2026, 9:00 – 10:00 AM |
The face writes the value in the current language, a range as the language writes one. length writes a day short, medium (the default) or long; before a day is chosen the face reads placeholder, the shared words “Choose a date” by default, in the title grey.
| Measure | Size |
|---|---|
| The field | A field’s face: one control high at the foot of its square, as wide as its words (it hugs them, as a button does; --ds-calendar-picker-width sets a width), the words 4px in, the chevron-down icon (16px) 2px from the end. |
| The days to type | A field one control high on its own square for the first day and one for the last; with times on, each day’s time on the square below it. One square spare after them. |
| The month | One square a day, seven squares wide: the month with its chevrons, the weekdays in a letter, six weeks with the neighbouring months’ days in the title grey. |
| The marks | The chosen days are squares with 4px corners in Sharp blue, the days between on a band of it, today a red disc. |
| Include time, Clear | One square each, the switch at the end, set off by one-square separators with a line through them. |
| The frame | A 1px line with half a square inside it, no shadow: eight squares wide. |
| Its place | Half a square below the field, or above it when there is more room there, kept on screen. |
Turning times on gives the first day 9:00 and the last 10:00, which the time fields change; with times on, the panel stays open after the second press so they can be set.
A typed day is read when the person presses Enter or leaves the field: 2026-10-21, or a date the browser can read such as “Oct 21, 2026”. Anything else puts the field back as it was.
required leaves Clear out and tells the form a value is missing. min and max limit the days. A form’s reset puts back the value the field started with. readDateValue, writeDateValue and parseTypedDay are exported for a page that reads or writes the value itself.
Events
Section titled “Events”Both calendars take the same events, as a property:
| Field | What it is |
|---|---|
title | What happens. |
start | The first day, YYYY-MM-DD. |
end | The last day, for something over several days. |
time | When it starts, written before the title in a month. |
color | A token or colour for its fill. Take it from the palette. |
count | How much it counts for in heat; one when left out. |
id | Anything the page needs back; the calendar leaves it alone. |
A day lists its events longest first, then by time.
Days and weeks
Section titled “Days and weeks”A day is written YYYY-MM-DD and stays on its date in every time zone. The week starts where the language starts it (Monday in most of Europe, Sunday in the United States and Japan); week-start sets it, 0–6 from Sunday or a day’s English name. Month and weekday names come from the current language.
min and max limit the days a person may choose: the days outside them are drawn faint and cannot be selected. today draws another day as today, for a preview or a test.
The day arithmetic the calendars use is DS1/0-face/calendar.ts, plain TypeScript without Lit: monthWeeks, addDays, addMonths, firstWeekday, weekdayNames, isoWeek, eventsByDay and the rest.
Accessibility
Section titled “Accessibility”- Each calendar is a grid named by its month (or
label), with one Tab stop on a day: the one moved to, the selected day, today, or the first. A selectable calendar isaria-multiselectable, and every day of the range isaria-selected. - The arrow keys move a day, or a week across the weeks; Home and End go to the week’s first and last day; Page Up and Page Down move a month, with Shift a year. A month moves on when the focus leaves it, and right to left the arrows turn round.
- Enter or Space presses the day. Each day is labelled with its whole date and what happens on it, and today is
aria-current="date"; a selectable calendar marks the selected day witharia-selected. - The arrows are named “Previous month” and “Next month” (“Previous year”, “Next year”, “Earlier years” and “Later years” among the months and years), and the month’s name is announced when it changes. The title button is named by the title and “Choose a month and year”. All the words are the shared words, in every language.
- A picker’s field is a button with
aria-haspopup="dialog"andaria-expanded, named bylabeland the value. Enter, Space or the down arrow opens the panel with the focus on the first chosen day (or today); a click opens it and leaves the focus on the field. The typed fields and times are named by the label and which end they are; the switch isrole="switch". Escape, a press outside, or the focus leaving closes the panel, and the focus goes back to the field.
ds-calendar
Section titled “ds-calendar”| Attribute | Type | Default | What it does |
|---|---|---|---|
month | string | The value’s month, or today’s | The month shown, YYYY-MM. |
value | string | "" | The selected day or range; in a picker, with or without times. |
selectable | boolean | false | Pressing a day selects it, or ends a range. |
picker | boolean | false | A field that opens the small month. |
compact | boolean | false | One square per day. |
day-width | number | 4 (1 compact) | Squares per day. |
lines | number | 2 | Lines of events under a date. |
week-numbers | boolean | false | The week’s number on its first day. |
fixed | boolean | false | Always six weeks. |
outside-days | boolean | false | The days of the months before and after, in the title grey. |
heat | boolean | false | Light each day by how much happens on it. |
heat-max | number | The busiest day shown | The amount that lights a day fully. |
no-header | boolean | false | Leave out the title and arrows. |
no-today | boolean | false | Leave out the Today button. |
min, max | string | — | The days a person may choose. |
week-start | string | The language’s | The week’s first day. |
today | string | The reader’s today | The day drawn as today. |
label | string | The month (a picker: “Date”) | The grid’s or the picker’s name; literal shows it as written. |
name | string | — | The form field’s name. |
placeholder | string | “Choose a date” | A picker’s words before a day is chosen. |
length | string | medium | How a picker writes a day. |
time | boolean | false | A picker chooses a time with each day (Include time). |
required | boolean | false | A form needs a value; Clear is left out. |
disabled | boolean | false | A picker cannot be opened. |
open | boolean | false | A picker’s panel is open. |
ds-calendar-large
Section titled “ds-calendar-large”| Attribute | Type | Default | What it does |
|---|---|---|---|
start | string | The month before today’s | The first month drawn, YYYY-MM. |
months | number | 6 | How many months are drawn. |
scale | number | 1.5 | How many times the grid it is drawn. |
value, selectable, min, max, week-start, today, label, no-header | As in a month. |
| Event | Detail | What it means |
|---|---|---|
day-press | { day, events } | A day was pressed, or chosen with Enter or Space. Cancel it to keep a selectable calendar’s value. |
change | { value, previous, start, end } | A person selected a day, or the end of a range. |
input | { value, previous, start, end } | A picker’s value changed, the same moment as change. |
ds-calendar-toggle | { open } | A picker’s panel opened or closed. |
event-press | { event, day } | An event was pressed (in a month). |
navigate | { month } | A person moved to another month. |
| Method | What it does |
|---|---|
previousMonth(), nextMonth() | Moves a month, as the arrows do. |
showToday() | Brings today’s month into view. |
showMonth(month) | Shows a month (ds-calendar). |
clear() | Empties the value, as Clear does, and fires change. |
show(), hide() | Opens or closes a picker’s panel. |
| Part | What it is |
|---|---|
header, title, previous, next, today | The title row and its buttons. |
picks, pick, foot, clear | The months or years, one of them (with selected and today), and Clear’s row and button. |
grid, weekdays | The grid and its weekday names. |
day, week, event, more | A month’s days, weeks, events and the +2 line; a day also carries today, selected and heat. |
cell, frame, scroller | The large calendar’s days, frame and scroller. |
trigger, popover, field, options, clear | A picker’s field, its panel, a row of a day or a time to type, and Include time and Clear. |
| Custom property | Default | What it sets |
|---|---|---|
--ds-calendar-today | var(--ds-red-for-blood) | Today’s disc. |
--ds-calendar-selected | var(--ds-sharp-blue) | The selected day and a range’s ends; the band between is it at 16%. |
--ds-calendar-event-fill | The fill (Apple green in the large calendar) | An event without a colour. |
--ds-calendar-line | 1px solid var(--ds-border-color) | A month’s lines. |
--ds-calendar-ink | var(--ds-text-color) | The large calendar’s lines and selected day. |
--ds-calendar-picker-width | Its words’ width | A picker’s field. |
--ds-calendar-heat-1 … -4 | The accent’s four steps | Heat’s fills. |
--ds-calendar-heat-ink-1 … -4 | The ink, or white on the dark steps | The date on each step. |
Activity squares
Section titled “Activity squares”Use activity on ds-calendar-large for a compact contribution-style grid.
It defaults to one grid square per day, separates the squares, and fills dates
with their event colours. Dates and event descriptions remain available to
assistive technology and in a tooltip. Use no-header for a fixed month.
<ds-calendar-large activity no-header start="2026-10" months="1"></ds-calendar-large>Set events as a property, as with the full calendar. Days without events stay
quiet; repeated events on one day do not increase the colour intensity.