Since NuxtLabs joined Vercel, Nuxt UI v4 will now include all the Pro components for free 🎉🥳. Party time!
This means that the Typography components like ProsePre
or ProseH2
will now be available for free.
Nuxt UI v4 is in alpha at the time of writing. I like living on the edge.
Like all real programmers, I'm lazy and would like to use the prebuilt typography components rather than writing my own. The issue, however, is that they are designed to work with Nuxt Content, not Sanity. However, with just a few lines of code, we can use them with Sanity.
Setup Guide
I'm assuming at this point that you have Sanity installed and set up and have a way to query and retrieve the content in Nuxt
1. Install @portabletext/vue
and @nuxt/ui
npm install --save @portabletext/vue @nuxt/ui slugify
yarn add @portabletext/vue @nuxt/ui slugify
pnpm add @portabletext/vue @nuxt/ui slugify
bun add @portabletext/vue @nuxt/ui slugify
2. Enable the Typography components in nuxt.config.ts
and ensure @nuxt/ui
is enabled
export default defineNuxtConfig({
modules: [
"@nuxt/ui",
],
ui: {
mdc: true,
}
})
Enabling the Typography components is done by setting mdc: true
in the @nuxt/ui
module config. This adds them to the auto-imports.
3. Use <PortableText>
<script setup lang="ts">
import {
PortableText,
type PortableTextVueComponents,
toPlainText,
} from "@portabletext/vue";
import {
ProseH1,
ProseH2,
ProseH3,
ProseH4,
ProseP,
ProseBlockquote,
ProseEm,
ProseStrong,
ProseCode,
ProseA,
ProseUl,
ProseOl
} from "#components";
import slugify from "slugify";
// TODO: Fetch from Sanity
const yourSanityBlocks = []
const components: Partial<PortableTextVueComponents> = {
block: {
// We use slugify and sanity's toPlainText to provide IDs for each heading for anchor links
h1: ({ value }, { slots }) =>
h(ProseH1, { id: slugify(toPlainText(value)) }, () => slots.default?.()),
h2: ({ value }, { slots }) =>
h(ProseH2, { id: slugify(toPlainText(value)) }, () => slots.default?.()),
h3: ({ value }, { slots }) =>
h(ProseH3, { id: slugify(toPlainText(value)) }, () => slots.default?.()),
h4: ({ value }, { slots }) =>
h(ProseH4, { id: slugify(toPlainText(value)) }, () => slots.default?.()),
blockquote: ProseBlockquote,
normal: ProseP,
},
marks: {
em: (_, { slots }) => h(ProseEm, () => slots.default?.()),
strong: (_, { slots }) => h(ProseStrong, () => slots.default?.()),
code: (_, { slots }) => h(ProseCode, () => slots.default?.()),
// Passes the href value and sets target="_blank" (new tab) for external links
link: ({ value }, { slots }) =>
h(
ProseA,
{
href: value?.href,
target: (value?.href || "").startsWith("http") ? "_blank" : undefined,
},
() => slots.default?.()
),
},
list: {
bullet: ProseUl,
number: ProseOl,
},
};
</script>
<template>
<PortableText
:value="yourSanityBlocks"
:components="components"
/>
</template>
Conclusion
And voila! You can now use Nuxt UI's Typography components with your Sanity blocks. In a future blog post, I will show how to get the ProsePre
component working with syntax highlighting by Shiki (like I have on this page). Happy coding!