How to Use

Guide on how to use Schema UI components in your project

Using Schema UI Components

Follow these steps to integrate Schema UI components into your project:

1. Copy the Component

Copy the desired component from the Schema UI library and paste it into your project's /components/ui folder.

2. Copy the Schema

Copy the corresponding schema and paste it into the /sanity/schemas/ folder in your project.

3. Copy the Query

Copy the related query and paste it into the /sanity/queries/ folder in your project.

4. Import the Schema to the main schema file /sanity/schema.ts and add it to the schema types array, for example:

import { type SchemaTypeDefinition } from "sanity";
// documents
import page from "./schemas/documents/page";
 
// Schema UI shared objects
import blockContent from "./schemas/blocks/shared/block-content";
import link from "./schemas/blocks/shared/link";
import { colorVariant } from "./schemas/blocks/shared/color-variant";
import { buttonVariant } from "./schemas/blocks/shared/button-variant";
import sectionPadding from "./schemas/blocks/shared/section-padding";
// Schema UI objects
// import only the schemas you need
import hero1 from "./schemas/blocks/hero/hero-1";
import sectionHeader from "./schemas/blocks/section-header";
import splitColumn from "./schemas/blocks/split/split-column";
import splitRow from "./schemas/blocks/split/split-row";
import gridCard from "./schemas/blocks/grid/grid-card";
import pricingCard from "./schemas/blocks/grid/pricing-card";
import gridRow from "./schemas/blocks/grid/grid-row";
import carousel1 from "./schemas/blocks/carousel/carousel-1";
import timelineRow from "./schemas/blocks/timeline/timeline-row";
import timelinesOne from "./schemas/blocks/timeline/timelines-1";
import cta1 from "./schemas/blocks/cta/cta-1";
 
export const schema: { types: SchemaTypeDefinition[] } = {
  types: [
    // documents
    page,
    post,
    author,
    category,
    // shared objects
    blockContent,
    link,
    colorVariant,
    buttonVariant,
    sectionPadding,
    // blocks
    hero1,
    sectionHeader,
    splitColumn,
    splitRow,
    gridCard,
    pricingCard,
    gridRow,
    carousel1,
    timelineRow,
    timelinesOne,
    cta1,
    // add more blocks
  ],
};

5. Add schema type into the blocks array of the page document schema in /sanity/schemas/documents/page.ts:

import { defineField, defineType } from "sanity";
import { Files } from "lucide-react";
import { orderRankField } from "@sanity/orderable-document-list";
 
export default defineType({
  name: "page",
  type: "document",
  title: "Page",
  icon: Files,
  groups: [
    {
      name: "content",
      title: "Content",
    },
    {
      name: "seo",
      title: "SEO",
    },
    {
      name: "settings",
      title: "Settings",
    },
  ],
  fields: [
    defineField({ name: "title", type: "string", group: "content" }),
    defineField({
      name: "slug",
      title: "Slug",
      type: "slug",
      group: "settings",
      options: {
        source: "title",
        maxLength: 96,
      },
      validation: (Rule) => Rule.required(),
    }),
    // add only the blocks you need
    defineField({
      name: "blocks",
      type: "array",
      group: "content",
      of: [
        { type: "hero-1" },
        { type: "section-header" },
        { type: "split-row" },
        { type: "grid-row" },
        { type: "carousel-1" },
        { type: "timeline-row" },
        { type: "cta-1" },
      ],
    }),
    defineField({
      name: "meta_title",
      title: "Meta Title",
      type: "string",
      group: "seo",
    }),
    defineField({
      name: "meta_description",
      title: "Meta Description",
      type: "text",
      group: "seo",
    }),
    defineField({
      name: "noindex",
      title: "No Index",
      type: "boolean",
      initialValue: false,
      group: "seo",
    }),
    defineField({
      name: "ogImage",
      title: "Open Graph Image - [1200x630]",
      type: "image",
      group: "seo",
    }),
    orderRankField({ type: "page" }),
  ],
});

6. Import the Query to the main page query file /sanity/queries/page.ts and add it to the blocks array, for example:

import { groq } from "next-sanity";
// import only the queries you need
import { hero1Query } from "./hero/hero-1";
import { sectionHeaderQuery } from "./section-header";
import { splitRowQuery } from "./split-row";
import { gridRowQuery } from "./grid/grid-row";
import { carousel1Query } from "./carousel/carousel-1";
import { timelineQuery } from "./timeline";
import { cta1Query } from "./cta/cta-1";
 
// query with all blocks, make sure to import only the blocks you need
export const PAGE_QUERY = groq`
  *[_type == "page" && slug.current == $slug][0]{
    blocks[]{
      ${hero1Query}
      ${sectionHeaderQuery}
      ${splitRowQuery}
      ${gridRowQuery}
      ${carousel1Query}
      ${timelineQuery}
      ${cta1Query}
    },
    meta_title,
    meta_description,
    noindex,
    ogImage {
      asset->{
        _id,
        url,
        metadata {
          dimensions {
            width,
            height
          }
        }
      },
    }
  }
`;

7. Import the Component to Blocks /components/blocks and add it to the componentMap, for example:

// import only the components you need
import Hero1 from "@/components/ui/hero/hero-1";
import SectionHeader from "@/components/ui/section-header";
import SplitRow from "@/components/ui/split/split-row";
import GridRow from "@/components/ui/grid/grid-row";
import Carousel1 from "@/components/ui/carousel/carousel-1";
import TimelineRow from "@/components/ui/timeline/timeline-row";
import Cta1 from "@/components/ui/cta/cta-1";
 
// map all components you need
const componentMap: { [key: string]: React.ComponentType<any> } = {
  "hero-1": Hero1,
  "section-header": SectionHeader,
  "split-row": SplitRow,
  "grid-row": GridRow,
  "carousel-1": Carousel1,
  "timeline-row": TimelineRow,
  "cta-1": Cta1,
};
 
export default function Blocks({ blocks }: { blocks?: Sanity.Block[] }) {
  return (
    <>
      {blocks?.map((block: Sanity.Block) => {
        const Component = componentMap[block._type];
        if (!Component) {
          // Fallback for unknown block types to debug
          return <div data-type={block._type} key={block._key} />;
        }
        return <Component {...block} key={block._key} />;
      })}
    </>
  );
}

8. Skip this step if you're using our latest Next.js Sanity Starter.

If you're not using our Next.js Sanity Starter:

  • add shared objects listed above in the step #4 under shared objects to your project;
  • add section-container.tsx to /components/ui folder;
import { cn } from "@/lib/utils";
 
export const DEFAULT_PADDING = {
 top: true,
 bottom: true,
};
 
export interface ISectionPadding {
 top: boolean;
 bottom: boolean;
}
 
export interface ISectionContainer {
 color?:
   | "primary"
   | "secondary"
   | "card"
   | "accent"
   | "destructive"
   | "background"
   | "transparent";
 children: React.ReactNode;
 className?: string;
 padding?: ISectionPadding | null | undefined;
}
 
export default function SectionContainer({
 color = "background",
 padding,
 children,
 className,
}: ISectionContainer) {
 return (
   <div
     className={cn(
       `bg-${color} relative`,
       padding?.top ? "pt-16 xl:pt-20" : undefined,
       padding?.bottom ? "pb-16 xl:pb-20" : undefined,
       className
     )}
   >
     <div className="container">{children}</div>
   </div>
 );
}
  • safelist classes used for background colors and grid columns in tailwind.config.js:
safelist: [
    "bg-background",
    "bg-primary",
    "bg-secondary",
    "bg-card",
    "bg-accent",
    "bg-descturctive",
    "bg-muted",
    "lg:grid-cols-2",
    "lg:grid-cols-3",
    "lg:grid-cols-4",
  ],