@multidots/sanity-blog-theme
v0.0.4
Published
Sanity Blog Theme by Multidots
Readme
Sanity Blog Theme (Next.js + Sanity v3)
Modern, editor-friendly starter that pairs Next.js (App Router) with Sanity Studio v3. It ships with a flexible Page Builder, a blog, SEO fields, and a curated Studio experience (Desk structure, grouped fields, icons, and collapsible inputs).
Highlights
- Page Builder with reusable blocks (Hero, CTA, Image & Text, Client Logos, Services, Testimonials, Team, Address)
- Organized editor UX: field groups, collapsible sections, sensible defaults, previews
- Sanity Studio embedded at
/studiowith a custom content structure - Blog with authors, categories, SEO, pagination-ready queries
Create a new project
The easiest way to get started is using the CLI:
npx @multidots/sanity-blog-theme my-blog-project
cd my-blog-projectOr using your preferred package manager:
# npm
npx @multidots/sanity-blog-theme my-blog-project
# yarn
yarn create @multidots/sanity-blog-theme my-blog-project
# pnpm
pnpm create @multidots/sanity-blog-theme my-blog-projector Directly clone the repository:
git clone https://github.com/multidots/sanity-blog.git
cd sanity-blog-themeThis will:
- Create a new directory with your project name
- Copy all template files
- Interactive Sanity setup - Configure your project with guided prompts
- Auto-generate .env.local - No manual environment setup needed
- Install dependencies automatically
- Set up a proper
.gitignorefile - Update
package.jsonwith your project name
🚀 Interactive Setup Process
The CLI will guide you through:
Sanity Project Configuration - Enter your project details:
- Project ID
- Dataset name (default: "production")
- API version (auto-suggested with current date)
Environment File Creation - Choose to:
- Create
.env.localwith your actual project details - Or get an
.env.exampletemplate for manual setup
- Create
Ready to Go - Your project will be fully configured and ready to run!
Project structure
Folder Structure
sanity-blog-theme/
├── public/ # Static assets
│ └── images/ # Image assets
├── src/ # Source code
│ ├── app/ # Next.js App Router
│ │ ├── (frontend)/ # Frontend route group
│ │ │ ├── [slug]/ # Dynamic page routes
│ │ │ └── blog/ # Blog routes
│ │ │ └── [slug]/ # Individual blog post routes
│ │ ├── api/ # API routes
│ │ │ └── submit-form/ # Form submission endpoint for contact form plugin integration
│ │ └── studio/ # Sanity Studio routes
│ │ └── [[...tool]]/ # Studio catch-all routes
│ ├── components/ # React components
│ │ └── blocks/ # Page Builder block components
│ └── sanity/ # Sanity configuration and schemas
│ ├── lib/ # Sanity utilities
│ └── schemaTypes/ # Content schemas
│ └── blocks/ # Block schemas for Page BuilderSanity Studio
- Config:
sanity.config.ts - Schemas:
src/sanity/schemaTypes/ - Custom Desk structure:
src/sanity/structure.ts - Contact Form:
@multidots/sanity-plugin-contact-formintegration
Studio is mounted at /studio via the Next.js App Router integration.
Content model (schemas)
Documents
page: Title, Slug, Content (Page Builder), SEOpost: Title, Slug, Author, Main Image, Categories, Published At, Body, SEOauthor: Name, Slug, Image, Biocategory: Title, Slug, DescriptionsiteSettings(singleton): General, Header (Logo, Menu), Footer (menus, social), Blog settings, Home page reference
Objects and blocks
pageBuilder: Array composing these blocks:hero: Headline/subtitle, background (image/color), alignment, colorsctaBlock: Heading, Subheading, Button (text/link/new tab), background (image/color), text colorimageTextSection: Title, portable description, main image (+alt/size), image position, buttonclientList: Title, logos (image + url/new tab)services: Title, services (title, text, background color)testimonialSlider: Title, testimonials (quote, author)team: Title, team (name, role, image, bg color)address: Title, address, phone, email
blockContent: Portable Text with basic marks, images, CTAs, etc.seo: Title override, description, image, noindex
Icons
- Blocks use icons from
@sanity/iconsfor a clearer insert menu and arrays.- For example:
hero(TextIcon),ctaBlock(BlockContentIcon),team(UsersIcon),address(PinIcon) - Change icons in each block schema under
src/sanity/schemaTypes/blocks/*Type.ts.
- For example:
Desk structure
Defined in src/sanity/structure.ts:
- Site Settings singleton pinned at the top
- Pages
- Blog → Posts, Categories, Authors
- Any other types appear in a fallback list
Frontend implementation
Rendering content
- Page Builder component:
src/components/PageBuilder.tsx- Maps each
_typein thepageBuilderarray to a React component insrc/components/blocks/* - Includes in-place editing data attributes via
next-sanityfor a smoother authoring workflow
- Maps each
Mobile Navigation
- Responsive hamburger menu with smooth slide animations
- Vertical mobile menu layout with professional styling
- Touch-friendly interactions and accessibility features
- Auto-close on navigation and click outside
Contact Form System
- Plugin:
@multidots/sanity-plugin-contact-formv1.0.5 - Features: Dynamic forms, file upload, reCAPTCHA, email notifications
- Documentation: Plugin Documentation
Queries
Queries live in src/sanity/lib/queries.ts and cover header/footer, sitemap, pages, posts, and settings.
PAGE_QUERYloads page content + SEOPOSTS_QUERY,POSTS_COUNT_QUERY,SINGLE_POST_QUERYpower the blogSITE_SETTINGS_QUERY,HEADER_QUERY,FOOTER_QUERYload global UI configSITEMAP_QUERYreturns URLs and update dates for pages and posts
Using the Page Builder
- Create a
Pagedocument in Studio - Add blocks to the
Contentgroup - Use the insert menu (grid view) to discover blocks; re-order via drag-and-drop
- Most blocks have grouped fields (Content, Style, etc.) and collapsible sub-objects for a clean editing experience
Contact Form Plugin
The project includes @multidots/sanity-plugin-contact-form for dynamic form creation and management. For detailed setup and usage instructions, visit the plugin documentation.
Blog
Content modeling
postdocuments referenceauthorandcategoryseoembedded per post
Frontend
- Blog listing and post page live under
src/app/(frontend)/blog - Pagination logic can use
POSTS_QUERY+POSTS_COUNT_QUERY - Posts per page driven by
siteSettings.blogPostsPerPage
Global settings
Singleton: siteSettings (enforced via Desk structure and restricted actions in sanity.config.ts).
Key fields
- General:
siteTitle - Header:
logo,menuItems(title, url, openInNewTab) - Footer:
footerTitle,footerDescription,footermenuItems,copyrightText,socialLinks - Pages:
homePagereference (used as the site’s homepage source) - Blog:
blogPostsPerPage,blogPageCTA
SEO
Each page and post has an seo object. Queries coalesce page/post title/description when SEO fields are left empty. noIndex can be toggled per document.
Add a new block
- Create the schema
- Add a new file under
src/sanity/schemaTypes/blocks/YourBlockType.ts - Follow the pattern in existing blocks: groups, fields, preview, icon
- Register the type
- Export it from
src/sanity/schemaTypes/index.ts - Add it to the
oflist insrc/sanity/schemaTypes/pageBuilderType.ts
- Build the React component
- Create
src/components/blocks/YourBlock.tsx - Match props to your schema fields
- Map it in the Page Builder
- Update the switch in
src/components/PageBuilder.tsxto render your component when_type === 'yourBlock'
- (Optional) Insert menu preview
- Add
/public/block-previews/yourBlock.pngto visualize the block in the Studio insert grid
Current Available Blocks: hero, ctaBlock, imageTextSection, clientList, services, testimonialSlider, team, address
Development
Common commands
npm run dev # Start Next.js app + Studio (mounted at /studio)
npm run build # Production build
npm run start # Start production serverSanity configuration
- Project/API vars are set via
src/sanity/env.ts - Studio plugins: Structure tool, Vision, Color input, Contact Form plugin
Troubleshooting
- Missing env var error
- The app throws a helpful error if
NEXT_PUBLIC_SANITY_PROJECT_IDorNEXT_PUBLIC_SANITY_DATASETis missing
- The app throws a helpful error if
- Studio not showing a type
- Ensure the type is exported in
src/sanity/schemaTypes/index.ts
- Ensure the type is exported in
License
MIT — feel free to use, modify, and distribute. Attribution is appreciated.
