- Home
- now
- Engineering
- Why We Simplified the Sanity Schema: An Editor-First Philosophy
Why We Simplified the Sanity Schema: An Editor-First Philosophy
If you've ever managed content in a traditional CMS, you know the feeling of dread when opening a page editor. Dozens of fields, endless tabs, and mysterious checkboxes that break the layout if you click them wrong. Developers often build these systems with the best intentions, offering maximum flexibility. But for editors, this "flexibility" is actually a burden.
The Paradox of Choice
When developers create schemas, the instinct is often to expose every possible CSS property as a field. "What if they want the background to be blue? Or red? Or a gradient? Let's add a color picker! And a padding slider! And a margin input!"
This leads to two major problems:
1. Inconsistency: Your brand identity dissolves as every page looks slightly different.
2. Cognitive Load: Editors spend more time designing the page than writing the content.
The NextMedal Approach: Decision Reduction
In this project, we've taken a radically different approach. We believe the schema should guide the editor, not overwhelm them. We focus on semantic meaning over visual tweaking.
1. Semantic Components, Not Visual Primitives
Instead of a generic "Box" component with 50 style options, we provide purpose-built modules like "Callout" or "Hero".
Here is how simple our Callout schema is. Notice how we limit the rich text options to exactly what makes sense for a callout—no random font sizes or colors.
export default defineType({
name: 'callout',
title: 'Callout',
type: 'object',
fields: [
defineField({
name: 'content',
title: 'Content',
type: 'array',
of: [
{
type: 'block',
// We strictly limit styles to keep the design consistent
styles: [
{ title: 'Normal', value: 'normal' },
{ title: 'Heading 2', value: 'h2' },
],
marks: {
decorators: [
{ title: 'Strong', value: 'strong' },
{ title: 'Emphasis', value: 'em' },
],
},
},
],
}),
defineField({
name: 'ctas',
title: 'Call-to-actions',
type: 'array',
of: [{ type: 'cta' }],
}),
],
});2. Smart Defaults & Collapsed Complexity
We know that sometimes you do need advanced options. But they shouldn't clutter the main view. We use fieldsets to hide advanced configuration by default, keeping the focus on content creation.
fieldsets: [
{
name: 'advanced',
title: 'Advanced Options',
options: { collapsible: true, collapsed: true }, // Hidden by default
},
],
fields: [
// ... core fields ...
{
...createUidField(),
fieldset: 'advanced', // Only visible if you need it
},
],3. Guardrails for Design System Integrity
We use validation to prevent broken layouts before they happen. For example, in our Hero component, we enforce that you can only have one "Primary" button, ensuring the user's attention is directed correctly.
defineField({
name: 'ctas',
validation: (Rule) =>
Rule.max(2).custom((ctas) => {
const primaryCount = ctas.filter(c => c.style === 'primary').length;
if (primaryCount > 1) return 'Only one Primary button is allowed';
return true;
}),
})The Result: Happier Editors
By taking away the burden of design choices, we empower editors to do what they do best: create great content. They can publish faster, knowing the system will handle the presentation perfectly every time.
This isn't just about code; it's about respect for the user. A good schema is an empathetic one.
