:is()<\/code> relational pseudo to optimize the code.<\/p>\n\n\n\nNotice that I\u2019m defining configurable CSS variables along the way (and prefixing them with ---kalel-<\/code> to avoid conflicts).<\/p>\n\n\n\nkal-el :is(ol, ul) {\n display: grid;\n font-size: var(--kalel-fz, small);\n grid-row-gap: var(--kalel-row-gap, .33em);\n grid-template-columns: var(--kalel-gtc, repeat(7, 1fr));\n list-style: none;\n margin: unset;\n padding: unset;\n position: relative;\n}<\/code><\/pre>\n\n\n\n <\/figure>\n\n\n\nLet\u2019s draw borders around the date numbers to help separate them visually:<\/p>\n\n\n\n
kal-el :is(ol, ul) li {\n border-color: var(--kalel-li-bdc, hsl(0, 0%, 80%));\n border-style: var(--kalel-li-bds, solid);\n border-width: var(--kalel-li-bdw, 0 0 1px 0);\n grid-column: var(--kalel-li-gc, initial);\n text-align: var(--kalel-li-tal, end); \n}<\/code><\/pre>\n\n\n\nThe seven-column grid works fine when the first day of the month is also<\/em> the first day of the week for the selected locale). But that\u2019s the exception rather than the rule. Most times, we\u2019ll need to shift the first day of the month to a different weekday.<\/p>\n\n\n\n <\/figure>\n\n\n\nRemember all the extra data-*<\/code> attributes we defined when writing our markup? We can hook into those to update which grid column (--kalel-li-gc<\/code>) the first date number of the month is placed on:<\/p>\n\n\n\n[data-firstday=\"1\"] [data-day=\"3\"]:first-child {\n --kalel-li-gc: 1 \/ 4;\n}<\/code><\/pre>\n\n\n\nIn this case, we\u2019re spanning from the first grid column to the fourth grid column \u2014 which will automatically \u201cpush\u201d the next item (Day 2) to the fifth grid column, and so forth.<\/p>\n\n\n\n
Let\u2019s add a little style to the \u201ccurrent\u201d date, so it stands out. These are just my styles. You can totally do what you\u2019d like here.<\/p>\n\n\n\n
[data-today] {\n --kalel-day-bdrs: 50%;\n --kalel-day-bg: hsl(0, 86%, 40%);\n --kalel-day-hover-bgc: hsl(0, 86%, 70%);\n --kalel-day-c: #fff;\n}<\/code><\/pre>\n\n\n\nI like the idea of styling the date numbers for weekends differently than weekdays. I\u2019m going to use a reddish color to style those. Note that we can reach for the :not()<\/code> pseudo-class to select them while leaving the current date alone:<\/p>\n\n\n\n[data-weekend]:not([data-today]) { \n --kalel-day-c: var(--kalel-weekend-c, hsl(0, 86%, 46%));\n}<\/code><\/pre>\n\n\n\nOh, and let\u2019s not forget the week numbers that go before the first date number of each week. We used a data-weeknumber<\/code> attribute in the markup for that, but the numbers won\u2019t actually display unless we reveal them with CSS, which we can do on the ::before<\/code> pseudo-element:<\/p>\n\n\n\n[data-weeknumber]::before {\n display: var(--kalel-weeknumber-d, inline-block);\n content: attr(data-weeknumber);\n position: absolute;\n inset-inline-start: 0;\n \/* additional styles *\/\n}<\/code><\/pre>\n\n\n\nWe\u2019re technically done at this point! We can render a calendar grid that shows the dates for the current month, complete with considerations for localizing the data by locale, and ensuring that the calendar uses proper semantics. And all we used was vanilla JavaScript and CSS!<\/p>\n\n\n\n
But let\u2019s take this one more step<\/em>\u2026<\/p>\n\n\nRendering an entire year<\/h3>\n\n\n Maybe you need to display a full year of dates! So, rather than render the current month, you might want to display all of the month grids for the current year.<\/p>\n\n\n\n
Well, the nice thing about the approach we\u2019re using is that we can call the render<\/code> method as many times as we want and merely change the integer that identifies the month on each instance. Let\u2019s call it 12 times based on the current year.<\/p>\n\n\n\nas simple as calling the render<\/code>-method 12 times, and just change the integer for month<\/code> \u2014 i<\/code>:<\/p>\n\n\n\n[...Array(12).keys()].map(i =>\n render(\n new Date(date.getFullYear(),\n i,\n date.getDate()),\n config.locale,\n date.getMonth()\n )\n).join('')<\/code><\/pre>\n\n\n\nIt\u2019s probably a good idea to create a new parent wrapper for the rendered year. Each calendar grid is a <kal-el><\/code> element. Let\u2019s call the new parent wrapper <jor-el><\/code>, where Jor-El is the name of Kal-El\u2019s father<\/a>.<\/p>\n\n\n\n<jor-el id=\"app\" data-year=\"true\">\n <kal-el data-firstday=\"7\">\n <!-- etc. -->\n <\/kal-el>\n\n <!-- other months -->\n<\/jor-el><\/code><\/pre>\n\n\n\nWe can use <jor-el><\/code> to create a grid for our grids. So meta!<\/p>\n\n\n\njor-el {\n background: var(--jorel-bg, none);\n display: var(--jorel-d, grid);\n gap: var(--jorel-gap, 2.5rem);\n grid-template-columns: var(--jorel-gtc, repeat(auto-fill, minmax(320px, 1fr)));\n padding: var(--jorel-p, 0);\n}<\/code><\/pre>\n\n\n