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";
import post from "./schemas/documents/post";
import author from "./schemas/documents/author";
import category from "./schemas/documents/category";
import faq from "./schemas/documents/faq";
import testimonial from "./schemas/documents/testimonial";
// 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 hero1 from "./schemas/blocks/hero/hero-1";
import hero2 from "./schemas/blocks/hero/hero-2";
import sectionHeader from "./schemas/blocks/section-header";
import splitRow from "./schemas/blocks/split/split-row";
import splitContent from "./schemas/blocks/split/split-content";
import splitCardsList from "./schemas/blocks/split/split-cards-list";
import splitCard from "./schemas/blocks/split/split-card";
import splitImage from "./schemas/blocks/split/split-image";
import splitInfoList from "./schemas/blocks/split/split-info-list";
import splitInfo from "./schemas/blocks/split/split-info";
import gridCard from "./schemas/blocks/grid/grid-card";
import pricingCard from "./schemas/blocks/grid/pricing-card";
import gridPost from "./schemas/blocks/grid/grid-post";
import gridRow from "./schemas/blocks/grid/grid-row";
import carousel1 from "./schemas/blocks/carousel/carousel-1";
import carousel2 from "./schemas/blocks/carousel/carousel-2";
import timelineRow from "./schemas/blocks/timeline/timeline-row";
import timelinesOne from "./schemas/blocks/timeline/timelines-1";
import cta1 from "./schemas/blocks/cta/cta-1";
import logoCloud1 from "./schemas/blocks/logo-cloud/logo-cloud-1";
import faqs from "./schemas/blocks/faqs";
import newsletter from "./schemas/blocks/forms/newsletter";
import allPosts from "./schemas/blocks/all-posts";
export const schema: { types: SchemaTypeDefinition[] } = {
types: [
// documents
page,
post,
author,
category,
faq,
testimonial,
// shared objects
blockContent,
link,
colorVariant,
buttonVariant,
sectionPadding,
// blocks
hero1,
hero2,
sectionHeader,
splitRow,
splitContent,
splitCardsList,
splitCard,
splitImage,
splitInfoList,
splitInfo,
gridCard,
pricingCard,
gridPost,
gridRow,
carousel1,
carousel2,
timelineRow,
timelinesOne,
cta1,
logoCloud1,
faqs,
newsletter,
allPosts,
],
};
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: "hero-2" },
{ type: "section-header" },
{ type: "split-row" },
{ type: "grid-row" },
{ type: "carousel-1" },
{ type: "carousel-2" },
{ type: "timeline-row" },
{ type: "cta-1" },
{ type: "logo-cloud-1" },
{ type: "faqs" },
{ type: "form-newsletter" },
{ type: "all-posts" },
],
}),
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 { hero2Query } from "./hero/hero-2";
import { sectionHeaderQuery } from "./section-header";
import { splitRowQuery } from "./split/split-row";
import { gridRowQuery } from "./grid/grid-row";
import { carousel1Query } from "./carousel/carousel-1";
import { carousel2Query } from "./carousel/carousel-2";
import { timelineQuery } from "./timeline";
import { cta1Query } from "./cta/cta-1";
import { logoCloud1Query } from "./logo-cloud/logo-cloud-1";
import { faqsQuery } from "./faqs";
import { formNewsletterQuery } from "./forms/newsletter";
import { allPostsQuery } from "./all-posts";
// 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},
${hero2Query},
${sectionHeaderQuery},
${splitRowQuery},
${gridRowQuery},
${carousel1Query},
${carousel2Query},
${timelineQuery},
${cta1Query},
${logoCloud1Query},
${faqsQuery},
${formNewsletterQuery},
${allPostsQuery},
},
meta_title,
meta_description,
noindex,
ogImage {
asset->{
_id,
url,
metadata {
dimensions {
width,
height
}
}
},
}
}
`;
export const PAGES_SLUGS_QUERY = groq`*[_type == "page" && defined(slug)]{slug}`;
7. Import the Component to Blocks /components/blocks
and add it to the componentMap
, for example:
import { PAGE_QUERYResult } from "@/sanity.types";
// import only the components you need
import Hero1 from "@/components/ui/hero/hero-1";
import Hero2 from "@/components/ui/hero/hero-2";
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 Carousel2 from "@/components/ui/carousel/carousel-2";
import TimelineRow from "@/components/ui/timeline/timeline-row";
import Cta1 from "@/components/ui/cta/cta-1";
import LogoCloud1 from "@/components/ui/logo-cloud/logo-cloud-1";
import FAQs from "@/components/ui/faqs";
import FormNewsletter from "@/components/ui/forms/newsletter";
import AllPosts from "@/components/ui/all-posts";
type Block = NonNullable<NonNullable<PAGE_QUERYResult>["blocks"]>[number];
// map the components to the block types
const componentMap: {
[K in Block["_type"]]: React.ComponentType<Extract<Block, { _type: K }>>;
} = {
"hero-1": Hero1,
"hero-2": Hero2,
"section-header": SectionHeader,
"split-row": SplitRow,
"grid-row": GridRow,
"carousel-1": Carousel1,
"carousel-2": Carousel2,
"timeline-row": TimelineRow,
"cta-1": Cta1,
"logo-cloud-1": LogoCloud1,
faqs: FAQs,
"form-newsletter": FormNewsletter,
"all-posts": AllPosts,
};
export default function Blocks({ blocks }: { blocks: Block[] }) {
return (
<>
{blocks?.map((block) => {
const Component = componentMap[block._type];
if (!Component) {
// Fallback for development/debugging of new component types
console.warn(
`No component implemented for block type: ${block._type}`
);
return <div data-type={block._type} key={block._key} />;
}
return <Component {...(block as any)} 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";
import { SectionPadding, ColorVariant } from "@/sanity.types";
interface SectionContainerProps {
color?: ColorVariant | null;
padding?: SectionPadding | null;
children: React.ReactNode;
className?: string;
}
export default function SectionContainer({
color = "background",
padding,
children,
className,
}: SectionContainerProps) {
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>
);
}