When I was building my personal website with Nuxt, I wanted something a bit more interesting than a plain text date next to each blog post.

I ended up creating a small date component which displays the day in a coloured block, with the month and year underneath in a ribbon shape. It’s a fairly simple design, but I think it looks much nicer than just displaying something like 20 Nov 2023.

Originally, the component lived directly in my website repository. It worked well, but I realised it wasn’t particularly specific to my blog, and I might want to use it on other websites.

So I moved it into its own repository and made the styling configurable.

How it works

The component takes a JavaScript Date object and splits it into three parts: the day, month and year.

There isn’t anything particularly complicated about the JavaScript. The day comes from getDate(), the month is converted into its three-letter abbreviation, and the year is shortened to its final two digits.

The template is just two elements inside a container.

1<template>
2 <div class="date">
3 <div class="day" v-text="getDay(date)" />
4 <div
5 class="monthYear"
6 v-text="`${getMonth(date)} '${getYear(date)}`"
7 />
8 </div>
9</template>
Copied!

For example, the 20th of November 2023 would be displayed as 20 in the top block and Nov '23 underneath.

Most of the appearance comes from CSS rather than JavaScript.

Creating the ribbon shape

The part I’m happiest with is the bottom of the date, which has a small notch cut out to make it look like a ribbon or bookmark.

Rather than using an image or an SVG, I used CSS clip-path.

1.monthYear {
2 width: 65px;
3 height: 48px;
4 margin-top: -1px;
5 padding-top: 4px;
6 background-color: var(--monthYearBackgroundColor);
7 clip-path: polygon(
8 0 0,
9 100% 0,
10 100% 100%,
11 50% 70%,
12 0 100%
13 );
14}
Copied!

The polygon defines five points around the element. The first four follow the edges, while the final point creates the notch in the bottom.

It’s a small detail, but it makes the component look much better than two rectangles stacked on top of each other. It also means the shape can be resized and recoloured without needing any additional assets.

Making the colours configurable

When the component was only used on my blog, I could just use the colours from the site’s stylesheet.

Once I moved it into its own repository, that wasn’t going to work particularly well. Another website might have a completely different colour scheme.

I added four props to control the text and background colours of each section.

1<template>
2 <NuxtDate
3 class="post__date"
4 :date="post.date"
5 day-text-color="#ffffff"
6 day-background-color="var(--green)"
7 month-year-text-color="#ffffff"
8 month-year-background-color="var(--grey)"
9 />
10</template
Copied!

The component passes these values into CSS custom properties on its container.

1<template>
2 <div
3 class="date"
4 :style="`
5 --dayTextColor: ${dayTextColor};
6 --dayBackgroundColor: ${dayBackgroundColor};
7 --monthYearTextColor: ${monthYearTextColor};
8 --monthYearBackgroundColor: ${monthYearBackgroundColor};
9 `"
10 >
11</template>
Copied!

This lets the component keep its own scoped styles, while allowing the parent application to control its appearance.

On my blog, I use a green background for the day and grey for the month and year, with white text on both.

Moving it into a separate repository

I didn’t feel the need to publish the component to npm. GitHub already provides everything needed to install a package directly from a repository.

The package has a package.json with index.vue as its entry point, so it can be installed using pnpm.

The original setup for Nuxt 2 registered the component globally using a Vue plugin.

Since moving my blog to Nuxt 3, the registration has changed slightly.

1import NuxtComponent_Date from 'nuxt-component-date/index.vue'
2import { defineNuxtPlugin } from '#imports'
3 
4export default defineNuxtPlugin((nuxtApp) => {
5 nuxtApp.vueApp.component(
6 'Date',
7 NuxtComponent_Date
8 )
9})
Copied!

Once registered, the component can be used anywhere in the application without importing it into each page.

Was it worth separating?

For a component with less than 100 lines of code, creating a separate repository might seem a bit excessive.

But I like having a collection of reusable components that I can install in different projects. If I decide to change the design or fix something, I can make the change in one place.

There are things I could improve. The component currently expects a JavaScript Date object rather than a string, and all four colour props are required. Giving those props sensible defaults would make it easier to drop into a new project.

The month names are also hardcoded in English, where Intl.DateTimeFormat would be a more flexible solution.

None of those are particularly important for what I’m using it for, though.

It’s a small component that does one thing, looks good, and saves me from recreating the same design whenever I need it.