Skip to content
Skip to main contentWhere does your team stand on AI adoption?
CONTACT SALESSTART BUILDING

Live preview Data models and custom fields

Publish

Use live previews to render edits in your data model without publishing them.

Although you can fetch Builder's Data Models using the Content API directly like a typical API resource, you can also use features such as live editing, previewing, and A/B testing of your Data Models within the Builder Visual Editor, all while using standard JS/TS syntax.

Prerequisites

To get the most out of this document, you should already be familiar with:

Importance of using live preview

Comparison of a view using live preview to edit data models vs a view that does not user live preview.

Live preview is crucial when working with custom fields, data models, and structured data in Builder. It offers several benefits:

  • Real-time updates by displaying changes immediately in the Visual Editor without publishing.
  • Improved user experience to meet your expectations with an intuitive experience.
  • Iterate more quickly on your content and designs more efficiently.
  • Make sure your Sections, Pages, and structured data are exactly as intended before publishing.

Live previewing can support a smoother experience, with changes in Custom Fields, Data Models, or Structured Data updates in real-time.

Live preview examples

Framework
Meta-Framework
SDK Generation
  1. Specify the name of your data model in BuilderContent with the model prop.
  2. Use a render prop pattern with the required data, an optional loading, and fullData parameters in case of SSR.
  3. Add code that accesses your data in the return() statement. This code varies and depends on your use case.
  4. Set the Preview URL on the data model. For detailed instructions on setting a Preview URL on a model, visit the Setting a persistent Preview URL on a model in Editing and Previewing Your Site.
  5. Test the live preview by editing your data model in the Builder Visual Editor and checking that the changes are reflected in your application.

The following snippet shows this structure.

// Add your data model's name <BuilderContent model="YOUR_DATA_MODEL"> // add function to render data {(data, loading, fullData) => { if (loading) return <div>Loading...</div>; return ( // Add your code to access your data ); }} </BuilderContent>

Custom fields in a blog post

This example uses a custom data model named blog-article, which includes a title, author, handle, and publishedDate fields, each of type text.

The component calls builder.get() to retrieve the published entry from the blog-article model by matching the urlPath to the route parameter.

The retrieved data is passed to BlogArticle component as a prop.

import { useEffect } from "react"; import { builder, BuilderContent, useIsPreviewing } from "@builder.io/react"; import { useParams } from "react-router"; import BlogArticle from "./BlogArticle"; builder.init(/* ADD YOUR PUBLIC API KEY HERE */); type ArticleData = { title: string; description: string; author: string; }; type Article = BuilderContent & { data: ArticleData; }; export default function BuilderPage() { const isPreviewingInBuilder = useIsPreviewing(); const [notFound, setNotFound] = React.useState(false); const [content, setContent] = React.useState<Article | null>(null); const { slug } = useParams(); // get the page content from Builder useEffect(() => { async function fetchContent() { const content = await builder .get("blog-article", { url: slug, }) .promise(); setContent(content); setNotFound(!content); if (content?.data.title) { document.title = content.data.title; } } fetchContent(); }, [slug]); if (content === null) { return; } if (notFound && !isPreviewingInBuilder) { return <div>404 Page Not Found</div>; } return ( <> {/* Render the Builder page */} <BlogContent article={content} /> </> ); }

The fetched article data is passed to the <BuilderContent> component for rendering. The inline function used within <BuilderContent> accepts the following parameters:

  • data (required) – The resolved data from the blog-article model. If A/B testing is active, <BuilderContent> automatically serves the winning variant without additional setup.
  • loading (optional) – A boolean indicating whether the data is still loading.
  • fullData (required for SSR) – Includes all raw data from the Content API, such as A/B variations and metadata. In client-side rendering, <BuilderContent> fetches the most recently published entry of the specified model if the content prop is not provided.
//app/src/components/BlogArticle.tsx import { BuilderComponent, BuilderContent, useIsPreviewing, } from "@builder.io/react"; type ArticleData = { title: string; description: string; author: string; }; type Article = BuilderContent & { data: ArticleData; }; export default function BlogContent({ article }: { article: Article }) { const isPreviewing = useIsPreviewing(); if (!isPreviewing && !article) { return ( <> <div>404 - Page Not Found</div> </> ); } return ( <> <BuilderContent content={article} options={{ includeRefs: true }} model="blog-article" > {(data, loading, fullData) => { return ( <> <!-- data coming from the blog-article data model --> <div>Blog Title: {data.title}</div> <div>Blog Author: {data.author}</div> <div>Blog handle: {data.handle}</div> {loading && <div>Loading...</div>} <!-- You can render builder components from Page/section model --> <BuilderComponent content={article} model="page" options={{ includeRefs: true }} /> <div>Published Date: {data.publishedDate.Default}</div> </> ); }} </BuilderContent> </> ); }

Fields such as title, author, handle, and publishedDate update in real time within the Visual Editor and do not require a publish action.

The <BuilderContent> component enables dynamic visual layouts for content entries and supports drag-and-drop editing.

An example with navigation links

This example uses a custom data model called site-settings, which includes a navigationLinks field of type list. Each link contains a linkURL and linkText sub-field.

import { BuilderContent } from "@builder.io/react"; export const Navigation = (props) => { return ( <BuilderContent model="site-settings"> {(data, loading, fullData) => { if (loading) { return <div>Loading...</div>; } else { return ( <> <ul> {data?.navigationLinks?.map((link) => { return ( <div key={link.linkUrl}> <a target="_blank" href={link.linkUrl}> {link.linkText} </a> </div> ); })} </ul> {props.children} </> ); } }} </BuilderContent> ); };

The BuilderContent component uses the site-settings data model to fetch the most recent published entry of the provided model for rendering.

The inline function provides three parameters:

  • data (required): The resolved data from the site-settings model is the structured data from the most recent entry. If A/B testing is active, <BuilderContent> automatically serves the winning variant without additional setup.
  • loading (optional): A boolean indicating whether the data is still loading.
  • fullContent (required for SSR): Includes all raw data from the Content API, such as A/B variations and metadata. In client-side rendering, <BuilderContent> fetches the most recently published entry of the specified model if the content prop is not passed.

The video below shows using this example data model in the Visual Editor:

What's next

For more information on the variety of custom fields, visit Custom Fields.

Was this article helpful?