Adding Language Badges to Code Blocks
[ web development · css · astro ]
A small enhancement I added that makes a big difference in readability: automatic language badges for code blocks.
The Problem
When I share code snippets, I noticed readers often benefit from knowing the programming language at a glance. While syntax highlighting provides visual cues, an explicit language indicator removes any ambiguity.
The Solution
I used CSS pseudo-elements and data attributes to automatically display language badges in the bottom-right corner of code blocks:
pre {
position: relative;
}
pre[data-language]::before {
content: attr(data-language);
position: absolute;
bottom: 8px;
right: 8px;
background: rgba(0, 0, 0, 0.7);
color: #fff;
padding: 2px 6px;
border-radius: 3px;
font-size: 0.7rem;
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
text-transform: uppercase;
letter-spacing: 0.5px;
z-index: 1;
}
I made the badge adapt to dark mode with a subtle transparency adjustment:
@media (prefers-color-scheme: dark) {
background: rgba(255, 255, 255, 0.2);
color: #ddd;
}
Implementation Details
My approach relies on:
- Relative positioning on the
pre
element to contain the absolutely positioned badge - CSS
attr()
function to pull the language name from adata-language
attribute - Bottom padding on code content to prevent overlap with the badge
- Responsive design that works in both light and dark themes
How Astro Makes This Possible
The magic happens during Astro’s content processing pipeline. When I write a code block in markdown like this:
```javascript
console.log('Hello, world!');
```
Astro’s markdown renderer automatically transforms it into HTML with the necessary data attribute:
<pre data-language="javascript">
<code>console.log('Hello, world!');</code>
</pre>
This seamless conversion is handled by Astro’s content collections system configured in src/content/config.ts
. During the static site generation process, Astro processes each markdown file in src/content/writing/
and applies syntax highlighting while preserving the language information as a data attribute. The CSS then uses attr(data-language)
to display this information as a badge - no JavaScript required.
Why Bottom-Right?
I chose to position the badge in the bottom-right corner because it keeps it visible without interfering with the code content. Unlike top-left placement, it doesn’t compete with natural reading flow or require additional top padding.
This enhancement works automatically with any markdown processor that adds language attributes to code blocks, making it a set-and-forget improvement to my code presentation.