How to override annotation styling in Portable Text Editor without losing functionality?
The trick to overriding the default styling from renderDefault while keeping its functionality is to wrap the rendered output in a custom element (like a span) with your own CSS classes. The renderDefault function applies Sanity's default styles to its children, but you can target those children with more specific CSS selectors to override them.
Here's the approach that works:
1. Create a custom annotation component that wraps renderDefault:
import { BlockAnnotationProps } from 'sanity'
import styles from './CustomAnnotation.module.css'
export const CustomAnnotationRenderer = (props: BlockAnnotationProps) => (
<span className={styles.customAnnotation}>{props.renderDefault(props)}</span>
)2. Use CSS to target the children elements and override Sanity's default styles:
The key is using the child selector (*) to target the elements that renderDefault creates. You'll also want to use !important to ensure your styles override Sanity's defaults. Here's an example that changes colors based on theme:
*[data-scheme='light'] .customAnnotation * {
border-color: #c123fc !important;
background-color: #f8e9fe;
}
*[data-scheme='dark'] .customAnnotation * {
border-color: #d97bfd !important;
background-color: #331440;
color: #fff;
}3. Register the custom component in your schema:
defineField({
name: 'internalLink',
title: 'Internal Link',
type: 'reference',
to: [{ type: 'page' }],
components: {
annotation: CustomAnnotationRenderer,
},
})For your use case with three different annotation types (internal links, external links, and defined terms), you'd create three separate renderer components, each with its own CSS module defining different colors. The wrapper span approach lets you scope your styles while renderDefault handles all the editor functionality like click interactions, hover states, and accessibility features.
You can inspect the rendered elements in your browser's developer tools to see exactly what HTML structure renderDefault creates, which helps you write more targeted CSS selectors if needed.
This solution comes from this community discussion where someone had the exact same need. For more context on customizing Portable Text annotations, check out the ultimate guide for customizing Portable Text.
Show original thread10 replies
Sanity β Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.