Working with Rich Text

Working with Rich Text

Rich Text in Val

Val's rich text is based on semantic HTML5 and provides a structured way to define formatted content. Unlike other CMS solutions, Val represents rich text as plain TypeScript objects, making it easy to understand, transform, and render.

Defining Rich Text Schema

Use s.richtext() to define a rich text field with configurable formatting options:

const articleSchema = s.object({
  content: s.richtext({
    style: {
      bold: true,
      italic: true,
      lineThrough: true,
    },
    block: {
      h1: true,
      h2: true,
      h3: true,
      // ... h4, h5, h6
      ul: true,
      ol: true,
    },
    inline: {
      a: true,
      img: true,
    },
  }),
});

Rich Text Structure

Rich text is represented as an array of block elements, where each element has a tag and children:

export default c.define("/content/article.val.ts", articleSchema, {
  content: [
    {
      tag: "h1",
      children: ["Getting Started with Val"],
    },
    {
      tag: "p",
      children: [
        "Val is a ",
        { tag: "span", styles: ["bold"], children: ["type-safe"] },
        " CMS that stores content as code.",
      ],
    },
    {
      tag: "ul",
      children: [
        {
          tag: "li",
          children: [{ tag: "p", children: ["Local-first development"] }],
        },
        {
          tag: "li",
          children: [{ tag: "p", children: ["No database required"] }],
        },
      ],
    },
  ],
});

Rendering Rich Text

Use the ValRichText component to render rich text in your React components:

import { ValRichText } from "@valbuild/next/client";
import { fetchVal } from "@/val/val.rsc";
import articleVal from "./article.val";

export default async function ArticlePage() {
  const { content } = await fetchVal(articleVal);
  
  return (
    <article>
      <ValRichText
        content={content}
        theme={{
          bold: "font-bold",
          italic: "italic",
          lineThrough: "line-through",
          h1: "text-4xl font-bold mb-4",
          h2: "text-3xl font-bold mb-3",
          p: "mb-4",
          ul: "list-disc pl-6 mb-4",
          ol: "list-decimal pl-6 mb-4",
        }}
      />
    </article>
  );
}

Theme Requirements

You can choose to render rich text without a theme if you don't need custom styling. However, if you provide a theme, TypeScript will require you to theme all the features you've enabled in your schema.

For example, if your schema includes bold, italic, and h1, your theme must provide styling for all three. This type-checking ensures you don't forget to update your theme when you extend your rich text schema with new features.

Available Options

Rich text supports three categories of formatting:

  • Styles: bold, italic, lineThrough, underline

  • Block elements: p, h1-h6, ul, ol, blockquote, code

  • Inline elements: a (links), img (images)

API Reference