CSS circular year calendar — Orbit example
A circular year calendar shows all twelve months on a single dial — useful as the centerpiece of a personal-planner app, a year-in-review dashboard, or a homepage hero that doubles as a real, glanceable date display. The metaphor is honest: a year is a cycle, and a circle expresses that more naturally than a 12-grid of rectangles.
This example layers four concentric rings (days, months, seasons, and event markers) around a central year label. The day numbers (1–30) ride on the outer ring as <o-arc> curved-text elements, the months and seasons sit on inner rings, and from-X rotations align each ring so the labels land exactly between the tick marks.
How it works
useRange(1, 30)plus.mapgenerates the 30 day-tickvectorelements and the 30 day-number<o-arc>elements without writing them by hand. In a vanilla project, generate them with a server template or a one-offforloop.<o-arc>for the month and season labels is what lets the text follow the curve of its ring. Because each<o-arc>is auto-distributed around its parentorbit-N, you only need to drop the labels in order — Orbit handles the angles.flipon the bottom-half labels (Apr–Sep, Summer) keeps them readable. Withoutflip, “Jun” on the bottom of the dial would render upside-down to anyone reading the calendar.from-Xring offsets (from-355,from-15,from-6) nudge each ring by a few degrees so the day ticks line up with the month boundaries instead of straddling them.- Two
vectormarkers withangle-60andangle-222highlight the current month and current day. Update them from JavaScript to make the calendar live.
Customization
Make it live by computing the angles from Date.now():
const now = new Date();const monthAngle = now.getMonth() * 30; // 12 months × 30°const dayAngle = (now.getDate() - 1) * 12; // ~30 days × 12°document.querySelector('.month').style.setProperty('--o-angle-composite', monthAngle + 'deg');document.querySelector('.day').style.setProperty('--o-angle-composite', dayAngle + 'deg');Color the seasons to make the dial readable at a glance:
.orbit-4 o-arc:nth-child(1) { --o-fill: #c8e6f5; } /* Winter */.orbit-4 o-arc:nth-child(2) { --o-fill: #d4f5c8; } /* Spring */.orbit-4 o-arc:nth-child(3) { --o-fill: #f5e8c8; } /* Summer */.orbit-4 o-arc:nth-child(4) { --o-fill: #f5d4c8; } /* Autumn */Switch the language of the month labels — replace “Jan, Feb, Mar…” with the equivalents in your locale. The layout is language-agnostic.
Related
- Calendar examples hub — including the Chronodex day planner
<o-arc>element reference- Smartwatch face example — uses the same
<o-arc>text-on-curve pattern
Use this in your project
Install Orbit CSS and the markup above gives you the entire calendar dial.