Thursday, April 9, 2026

Choosing a Date Vary in CSS


A date vary selector lets customers choose a timeframe between a begin and finish date, which is helpful in reserving journeys, sorting information by date blocks, choosing time slots, and planning schedules.

Instance pulled from Airbnb

I’m going to point out you an instance the place, though JavaScript is concerned, the majority of the work is dealt with by the “n of selector(s)” syntax of the CSS :nth-child selector, making it straightforward to construct the vary choice.

The “n of selector” syntax

This syntax of the :nth-child selector filters parts by a given selector first amongst all of the youngster parts, earlier than choosing them by a counting order.

The reclamation of land...

The primary reclamations might be traced...

By 1996, a complete of...

A lot reclamation has taken...

Hong Kong legislators...

.accent {
  coloration: pink;
}
.accent:nth-child(2) {
  font-weight: daring; /* doesn't work */
}
:nth-child(2 of .accent){
  text-decoration: underline;
}

There are two .accent-ed paragraphs with pink textual content. As we attempt to goal the second accented paragraph, .accent:nth-child(2) fails to pick it as a result of it’s looking for an .accent aspect that’s the second youngster of its guardian.

Whereas, :nth-child(2 of .accent) succeeds in choosing and styling the second accented paragraph as a result of it’s solely searching for the second aspect among the many **.accent** parts quite than the second of the entire kids.

The Format

Shifting onto our most important instance, let’s put collectively a month structure. It solely takes just a few strains of CSS.

#calendar {
  show: grid;
  grid-template-columns: repeat(7, 1fr); /* 7 for no. of days in per week */
}

Select Solely Two Dates

Now's once we attain for JavaScript since we are able to’t examine/uncheck a management in CSS. However even right here the “n of selector” syntax might be very helpful.

After we choose two dates to create a spread, clicking on a 3rd date will replace the vary and take away one of many earlier dates.

You may arrange the vary re-adjustment logic in any method you want. I’m utilizing this method: If the third date is both earlier or later than the final return date, it turns into the new return date, and the outdated one is unselected. If the third date is sooner than the final onward date, it turns into the brand new onward date, and the outdated one is unselected.

const CAL = doc.getElementById('calendar');
const DT = Array.from(CAL.getElementsByClassName('date')); 

CAL.addEventListener('change', e => {
  if (!CAL.querySelector(':checked')) return;
  
  /* When there are two checked containers, calendar will get 'isRangeSelected' class  */
  CAL.className = CAL.querySelector(':nth-child(2 of :has(:checked))') ? 'isRangeSelected':'';

  /* When there are three checked containers */
  if (CAL.querySelector(':nth-child(3 of :has(:checked))')) {

    change (DT.indexOf(e.goal.parentElement)) {

      /* If the newly checked date is first among the many checked ones, 
          the second checked is unchecked. Onward date moved earlier. */
      case DT.indexOf(CAL.querySelector(':nth-child(1 of :has(:checked))')):
      CAL.querySelector(':nth-child(2 of :has(:checked)) enter').checked = 0; 
      break;

      /* If the newly checked date is second among the many checked ones, 
          the third checked is unchecked. Return date moved earlier. */
      case DT.indexOf(CAL.querySelector(':nth-child(2 of :has(:checked))')):
      CAL.querySelector(':nth-child(3 of :has(:checked)) enter').checked = 0; 
      break;

      /* If the newly checked date is third among the many checked ones, 
          the second checked is unchecked. Return date moved later. */
      case DT.indexOf(CAL.querySelector(':nth-child(3 of :has(:checked))')):
      CAL.querySelector(':nth-child(2 of :has(:checked)) enter').checked = 0; 
      break;

    }
  }
});

First, we get the index of the present checked date (DT.indexOf(e.goal.parentElement)), then we see if that’s the identical as the primary checked amongst all of the checked ones (:nth-child(1 of :has(:checked))), second (:nth-child(2 of :has(:checked))), or third (:nth-child(3 of :has(:checked))). Provided that, we then uncheck the related field to revise the date vary.

You’ll discover that through the use of the “n of selector” syntax, focusing on the :checked field we would like by its place amongst all checked ones is made a lot easier — as a substitute of indexing via an inventory of checked dates in JavaScript for this, we are able to instantly choose it.

Styling the vary is even simpler than this.

Styling the Vary

/* When two dates are chosen */
.isRangeSelected { 
  /* Dates following the primary however not the second of chosen */
  :nth-child(1 of :has(:checked)) ~ :not(:nth-child(2 of :has(:checked)) ~ .date) {
    /* Vary coloration */
    background-color: rgb(228 239 253); 
  }
}

When there are two dates chosen, the dates between the primary (1 of :has(:checked)) and second (2 of :has(:checked)) are coloured pale blue, creating a visible vary for that block of dates within the month.

A calendar month layout with the dates 9-29 selected. 9 and 19 have a dark blue background and the dates between are light blue.

The colour is asserted inside a compound selector that selects dates (.date) following the to start with checked date (:nth-child(1 of :has(:checked))), however not the second of all checked date (:not(:nth-child(2 of :has(:checked))).

Right here’s the complete instance as soon as once more:

Related Articles

Latest Articles