Days Left This Year
Layout Variations
See how this plugin adapts across different mashup views. Each view shows a single instance to demonstrate how the layout responds to available space.
Full View
value
Days Passed
value
Days Left
<div class="layout layout--col gap--large">
<div class="grid grid--cols-10">
<div class="col col--span-1" />
<div class="col col--span-4">
<div class="item">
<div class="meta" />
<div class="content text--center">
<span class="value value--xxxlarge days_passed" data-value-fit="true">value</span>
<span class="label">Days Passed</span>
</div>
</div>
</div>
<div class="col col--span-4">
<div class="item">
<div class="meta" />
<div class="content text--center">
<span class="value value--xxxlarge days_left" data-value-fit="true">value</span>
<span class="label">Days Left</span>
</div>
</div>
</div>
<div class="col col--span-1" />
</div>
<div class="w--full">
<div id="days_left" data-today="2025-09-15T10:29:35+05:30" />
</div>
</div>
<div class="title_bar">
<img class="image" alt="" src="https://usetrmnl.com/images/plugins/days_left_year--render.svg" />
<span class="title">Days Left This Year</span>
<span class="instance">2026</span>
</div>
Half Horizontal
value
Days Passed
value
Days Left
<div class="layout">
<div class="flex flex--col gap--large" style="width: 200px">
<div class="item">
<div class="meta" />
<div class="content">
<span class="value days_passed">value</span>
<span class="label">Days Passed</span>
</div>
</div>
<div class="item">
<div class="meta" />
<div class="content">
<span class="value days_left">value</span>
<span class="label">Days Left</span>
</div>
</div>
</div>
<div class="grid grid--cols-2">
<div class="w--full">
<div id="days_left" data-today="2025-09-15T10:29:35+05:30" />
</div>
</div>
</div>
<div class="title_bar">
<img class="image" alt="" src="https://usetrmnl.com/images/plugins/days_left_year--render.svg" />
<span class="title">Days Left This Year</span>
<span class="instance">2026</span>
</div>
Half Vertical
value
Days Passed
value
Days Left
<div class="layout layout--col gap--large">
<div class="grid grid--cols-2">
<div class="item">
<div class="meta" />
<div class="content">
<span class="value value--small days_passed">value</span>
<span class="label">Days Passed</span>
</div>
</div>
<div class="item">
<div class="meta" />
<div class="content">
<span class="value value--small days_left">value</span>
<span class="label">Days Left</span>
</div>
</div>
</div>
<div class="w--full">
<div id="days_left" data-today="2025-09-15T10:29:35+05:30" />
</div>
</div>
<div class="title_bar">
<img class="image" alt="" src="https://usetrmnl.com/images/plugins/days_left_year--render.svg" />
<span class="title">Days Left This Year</span>
<span class="instance">2026</span>
</div>
Quadrant
value
Days Passed
value
Days Left
<div class="layout layout--col gap--large">
<div class="grid grid--cols-2">
<div class="item">
<div class="meta" />
<div class="content">
<span class="value value--small days_passed">value</span>
<span class="label">Days Passed</span>
</div>
</div>
<div class="item">
<div class="meta" />
<div class="content">
<span class="value value--small days_left">value</span>
<span class="label">Days Left</span>
</div>
</div>
</div>
<div class="w--full">
<div id="days_left" data-today="2025-09-15T10:29:35+05:30" />
</div>
</div>
<div class="title_bar">
<img class="image" alt="" src="https://usetrmnl.com/images/plugins/days_left_year--render.svg" />
<span class="title">Days Left This Year</span>
<span class="instance">2026</span>
</div>
Shared
This plugin uses a shared file that contains shared CSS styles and/or JavaScript logic used across all layout variations.
#days_left {
width: 689px;
height: 147px;
overflow: hidden;
margin-left: 34px;
column-count: auto;
column-fill: auto;
column-width: 13px;
column-gap: 0px;
}
#days_left .day {
width: 11px;
height: 19px;
float: left;
border-radius: 4px;
margin: 0px 0px 2px 0px;
break-inside: avoid-column;
}
.view--quadrant #days_left {
width: 318px;
height: 70px;
column-width: 6px;
margin-top: 0;
padding-left: 0;
margin-left: 0px;
}
.view--quadrant #days_left .day {
width: 5px;
height: 9px;
border-radius: 2px;
margin: 0 0 1px 0;
}
.view--half_vertical #days_left {
width: 318px;
height: 315px;
column-width: 6px;
margin-top: 0;
padding-left: 0;
margin-left: 0px;
}
.view--half_vertical #days_left .day {
width: 5px;
height: 43px;
margin: 0 0 2px 0px;
}
.view--half_horizontal #days_left {
width: 583px;
height: 147px;
column-width: 11px;
margin-top: 0;
padding-left: 0;
margin-left: 0;
margin-right: 7px;
}
.view--half_horizontal #days_left .day {
width: 9px;
height: 19px;
}
document.addEventListener('DOMContentLoaded', () => {
const yearContainers = document.querySelectorAll('#days_left');
const today = yearContainers[0].dataset['today'];
const now = new Date(today);
// Get the offset for the first day of the year (e.g. start of week is Mon and Jan 1 is Wed -> 2 days)
let firstDayOfWeek = 1; // 0=Sunday, 1=Monday, etc.
function createYearDivs(container) {
container.innerHTML = ''; // Clear the container before adding new divs
const totalDays = getDaysInYear(now.getFullYear());
const dayOffset = getDayOffset(firstDayOfWeek);
// Add empty divs for pre-January 1st days of first week
for (let i = 0; i < dayOffset; i++) {
const dayDiv = document.createElement('div');
dayDiv.classList.add('day', 'offset', 'bg-white');
container.appendChild(dayDiv);
}
// Add actual days
for (let i = 0; i < totalDays; i++) {
const dayDiv = document.createElement('div');
dayDiv.classList.add('day');
container.appendChild(dayDiv);
}
}
function updatePassedDays(container) {
const daysPassed = getYearProgress(now);
const dayDivs = Array.from(container.getElementsByClassName('day'))
.filter(day => !day.classList.contains('offset'));
// Highlight passed days
for (let i = 0; i < daysPassed; i++) {
dayDivs[i].classList.add('passed', 'bg--gray-4', '2bit:bg--gray-50');
}
for (let i = daysPassed; i < dayDivs.length; i++) {
dayDivs[i].classList.add('today', 'bg--gray-5', '2bit:bg--gray-65');
}
// Highlight the current day
if (dayDivs[daysPassed]) {
dayDivs[daysPassed].classList.remove('bg--gray-5', '2bit:bg--gray-65');
dayDivs[daysPassed].classList.add('bg-black');
}
// Update metric values
const daysPassedElements = document.querySelectorAll('.days_passed');
const daysLeftElements = document.querySelectorAll('.days_left');
daysPassedElements.forEach(element => {
element.textContent = daysPassed;
});
daysLeftElements.forEach(element => {
element.textContent = dayDivs.length - daysPassed;
});
}
function getDaysInYear(year) {
return isLeapYear(year) ? 366 : 365;
}
function isLeapYear(year) {
return year % 400 === 0 || (year % 100 !== 0 && year % 4 === 0);
}
function getFirstDay() {
return new Date(now.getFullYear(), 0, 1).getDay(); // what day of the week is Jan 1st
}
function getDayOffset() {
return (getFirstDay() - firstDayOfWeek + 7) % 7; // Offset based on preference
}
function getYearProgress(date) {
const startOfYear = new Date(date.getFullYear(), 0, 1);
const startOffset = startOfYear.getTimezoneOffset();
const currentOffset = date.getTimezoneOffset();
const offsetDifference = (startOffset - currentOffset) * 60 * 1000;
const diff = (date - startOfYear) + offsetDifference;
const oneDay = 1000 * 60 * 60 * 24;
return Math.floor(diff / oneDay);
}
yearContainers.forEach(container => {
createYearDivs(container);
updatePassedDays(container);
});
});