Customized Code highlighting in Nuxt
Published on: Thursday, November 28, 2024
Introduction
In modern web development, presenting code snippets in a visually appealing and readable format is crucial for enhancing the user experience, especially in documentation or technical blogs. If you're building a Nuxt application and want to include Markdown content with syntax-highlighted code blocks, you're in luck. With the power of the @nuxt/content module and the Shiki syntax highlighter, adding beautiful, customizable code highlighting to your Markdown files is a breeze. In this blog post, I'll walk you through the steps to seamlessly integrate syntax highlighting into your Nuxt app, so your code examples look polished and professional.
Problem Statement
To be able to customize code highlighting component using Shiki without opting for Nuxt UI Pro's Codeblock Component. This component provides extra features that are not included in the basic version, such as:
Automatic Icons
Ability to inject icons into ProsePre Components
Copy Functionality
A default copy button that allows for grabbing the code without selection
File Name Injection
Allows for filename and meta data injection to the component
Being a proponent of open-source and free technology, I didn't want to pay for Nuxt UI Pro's subscription. And since Nuxt Content's Markdown can be supercharged with Vue Components, I went ahead and wrote one myself - which is pretty simple to do and hence wanted to share.
This blog should provide a template on how to customize the default ProsePre Component in Nuxt. I am using the same Component in Markdown as in this blog. Let's get started! 🚀
Customizing the default ProsePre Component
It is as simple as defining and overwriting the existing ProsePre Component as described in the documentation. Simply create the following file:
<template>
<div class="code-block">
<span v-if="filename" class="file-name">{{ filename }}</span>
<pre :class="$props.class"><slot /></pre>
<button @click="copyToClipboard">
Copy
<span v-if="copied" class="tick-mark">✔</span>
</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
// Define props
const props = defineProps({
code: {
type: String,
default: ''
},
language: {
type: String,
default: null
},
filename: {
type: String,
default: null
},
highlights: {
type: Array as () => number[],
default: () => []
},
meta: {
type: String,
default: null
},
class: {
type: String,
default: null
}
});
const copied = ref(false);
// Copy function
const copyToClipboard = () => {
navigator.clipboard
.writeText(props.code)
.then(() => {
copied.value = true; // Show tick mark
setTimeout(() => (copied.value = false), 2000); // Hide after 2 seconds
})
.catch(() => alert('Failed to copy code.'));
};
</script>
<style scoped>
.code-block {
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 1rem;
font-family: 'Courier New', Courier, monospace;
position: relative;
margin-bottom: 1rem;
}
.file-name {
display: block;
font-weight: bold;
margin-bottom: 8px;
}
pre {
margin: 0;
padding: 12px;
background: #282c34;
color: #ffffff;
overflow: auto;
border-radius: 4px;
}
button {
margin-top: 8px;
padding: 8px 12px;
border: none;
color: white;
cursor: pointer;
border-radius: 4px;
font-size: 14px;
}
button:hover {
background-color: #0056b3;
}
.tick-mark {
color: #28a745;
margin-left: 8px;
font-size: 14px;
animation: fade-in-out 2s ease-in-out;
}
@keyframes fade-in-out {
0% {
opacity: 0;
}
20% {
opacity: 1;
}
80% {
opacity: 1;
}
100% {
opacity: 0;
}
}
pre code .line {
display: block;
}
</style>
Usage
With the new ProsePre Component defined, you should be able to use it as is - like you would the default version. Pass the file-type and file name, and you should see a rendered Vue component as above.
Conclusion
With just a few steps and the help of a simple component, you can fully customize the look and feel of code highlighting in your Nuxt Markdown-based content. By leveraging the flexibility of the @nuxt/content module and the powerful Shiki highlighter, you have complete control over themes, language support, and presentation. Whether you're building a technical blog, documentation, or any app showcasing code snippets, this approach ensures your content is both visually appealing and easy to read. Start experimenting with themes and customizations to make your code truly stand out!