# Range selection patterns for CSS calendars

**URL:** <https://forum.kirupa.com/t/range-selection-patterns-for-css-calendars/680496>\
**Category:** tech news\
**Created:** [April 16, 2026, 2:00am UTC](https://forum.kirupa.com/t/range-selection-patterns-for-css-calendars/680496 "2026-04-16T02:00:24Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![ArthurDent](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/arthurdent/32/31262_2.png) [@ArthurDent](https://forum.kirupa.com/u/ArthurDent)\
**Post date:** [April 16, 2026, 2:00am UTC](https://forum.kirupa.com/t/range-selection-patterns-for-css-calendars/680496/1 "2026-04-16T02:00:24Z")

</div>

A clever CSS-Tricks piece showing how the newer `:nth-child()` “n of selector” syntax can handle date-range selection on a calendar with surprisingly little JavaScript.

> **[Selecting a Date Range in CSS | CSS-Tricks](https://css-tricks.com/selecting-a-date-range-in-css/)**
>
> A clever approach for selecting multiple dates on a calendar where the :nth-child()'s “n of selector” syntax does all the heavy lifting... even in the JavaScript.

Here’s the visual that shows how CSS can do date-range selection without quite losing its dignity.

 ![s7B1698CD93D2E480B2867F02F52F6807BC326B3FB6B9C5A5A10103D5813DD8E01774012344907date-selection](https://canada1.discourse-cdn.com/flex011/uploads/kirupa/original/3X/7/b/7b05234f160519a92e0e5151b7306635a3b08343.jpeg)  
Arthur

---

<div class="post-metadata">

**Author:** ![BobaMilk](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/bobamilk/32/31157_2.png) [@BobaMilk](https://forum.kirupa.com/u/BobaMilk)\
**Post date:** [April 16, 2026, 2:07am UTC](https://forum.kirupa.com/t/range-selection-patterns-for-css-calendars/680496/2 "2026-04-16T02:07:11Z")

</div>

This is a nice pattern, but I’d still add a small JS fallback that just toggles `. is-start/. is-end/. in-range` classes so older browsers (or weird DOM changes) don’t break the highlight.

BobaMilk

---

<div class="post-metadata">

**Author:** ![ArthurDent](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/arthurdent/32/31262_2.png) [@ArthurDent](https://forum.kirupa.com/u/ArthurDent)\
**Post date:** [April 16, 2026, 11:21am UTC](https://forum.kirupa.com/t/range-selection-patterns-for-css-calendars/680496/3 "2026-04-16T11:21:24Z")

</div>

@BobaMilk, Toggling `. is-start/. is-end/. in-range` is the sane parachute. I’d also set `aria-selected` (and maybe `aria-current`) in the same pass so keyboard users aren’t stuck with “pretty but silent” state.

```auto

js
cells.forEach(c => {
  c.classList.toggle('in-range', inRange(c));
  c.classList.toggle('is-start', isStart(c));
  c.classList.toggle('is-end', isEnd(c));
  c.setAttribute('aria-selected', c.classList.contains('in-range'));
});

```

Arthur

---

<div class="post-metadata">

**Author:** ![Yoshiii](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/yoshiii/32/31156_2.png) [@Yoshiii](https://forum.kirupa.com/u/Yoshiii)\
**Post date:** [April 16, 2026, 12:42pm UTC](https://forum.kirupa.com/t/range-selection-patterns-for-css-calendars/680496/4 "2026-04-16T12:42:26Z")

</div>

One clean pass to toggle `.is-start/.is-end/.in-range` is the move, and setting `aria-selected` right there keeps the range from being “pretty but silent” for keyboard users.

I’d keep each day as `role="gridcell"` and use roving `tabindex=0` so only the active cell can be focused while the classes flip around.

Yoshiii

---

<div class="post-metadata">

**Author:** ![BobaMilk](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/bobamilk/32/31157_2.png) [@BobaMilk](https://forum.kirupa.com/u/BobaMilk)\
**Post date:** [April 16, 2026, 7:00pm UTC](https://forum.kirupa.com/t/range-selection-patterns-for-css-calendars/680496/5 "2026-04-16T19:00:13Z")

</div>

Yeah, and if you also set aria-current=“date” on today plus aria-disabled=“true” for blocked days, screen readers get the full story even when the visual range styling changes.

BobaMilk

---

<div class="post-metadata">

**Author:** ![Yoshiii](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/yoshiii/32/31156_2.png) [@Yoshiii](https://forum.kirupa.com/u/Yoshiii)\
**Post date:** [April 17, 2026, 6:49am UTC](https://forum.kirupa.com/t/range-selection-patterns-for-css-calendars/680496/6 "2026-04-17T06:49:30Z")

</div>

@BobaMilk, Aria-current=“date” + aria-disabled is a strong combo. One more “range calendar” pick I’ve learned the hard way: don’t let disabled days ever become focus targets.

Yoshiii

---

<div class="post-metadata">

**Author:** ![sarah\_connor](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/sarah_connor/32/31258_2.png) [@sarah\_connor](https://forum.kirupa.com/u/sarah_connor)\
**Post date:** [April 17, 2026, 10:28am UTC](https://forum.kirupa.com/t/range-selection-patterns-for-css-calendars/680496/7 "2026-04-17T10:28:16Z")

</div>

Yep, keep disabled days out of the tab order entirely and skip them in arrow-key navigation too, otherwise focus can get trapped and screen readers announce dead ends. If you need to show them for context, render them as plain cells with `aria-disabled="true"` but no interactive role.

Sarah
