@multidots/sanity-plugin-hero-block
v1.0.4
Published
Hero Block plugin for Sanity
Readme
Sanity Plugin Hero Block
A comprehensive and customizable hero block plugin for Sanity Studio v3 with support for images, videos, overlays, and call-to-action buttons.
Features
📝 Content Management
- Heading and subheading text fields
- Content alignment options (left, center, right)
- Customizable text colors
🔘 Call-to-Action Button
- Optional button with custom text
- Link support (internal and external URLs)
- Open in new tab option
🎨 Styling & Background Options
- Background Type: Choose between color or media
- Color: Hex color picker for solid backgrounds
- Media: Choose between image or video
- Image: Upload images through Sanity asset integration
- Video: Two video options
- Upload Video: Upload video files (MP4, WebM, OGG support)
- YouTube/Vimeo: Embed external videos (YouTube, Vimeo)
- Overlay Settings:
- Color overlay for media backgrounds
- Adjustable opacity settings
- Styling Options
- Button background and text color customization
- Content text color options
📱 Responsive Design
- Mobile-first responsive layout
- Optimized for all device sizes
🔧 Developer Features
- TypeScript support with full type definitions
- Self-contained styling with styled-components
- Sanity v3/v4 compatible
- Comprehensive error handling and asset fallbacks
Available Fields
Content
- Heading Text - Main hero title that appears prominently at the top of the block, ideal for grabbing attention with key messaging
- Subheading - Secondary descriptive text positioned below the heading to provide additional context or supporting information
- Content Alignment - Control text positioning with left, center, or right alignment options to match your design needs
- Text Color - Customize the color of all text content using hex values to ensure brand consistency and readability
Call-to-Action Button
- Button Text - Customizable button label text to create compelling calls-to-action that drive user engagement
- Button Link - Set destination URLs for both internal page navigation and external website links
- Open in New Tab - Toggle option to open linked pages in a new browser tab, ideal for external resources
- Button Colors - Full control over button appearance with separate background and text color customization
Background Options
- Background Type - Flexible choice between a solid color background or rich media (images/videos) to suit different design needs
- Background Color - Select any color using a hex color picker when a solid background is preferred
- Background Media - Upload and manage both image and video assets directly through Sanity's asset pipeline
- Video Source - Choose between uploading your own video files or embedding videos from YouTube and Vimeo platforms
Overlay Settings
- Overlay Color - Add a colored overlay layer on top of media backgrounds to improve text readability or create visual effects
- Overlay Opacity - Fine-tune the transparency level of the color overlay from 0% (fully transparent) to 100% (fully opaque)
Installation
npm install @multidots/sanity-plugin-hero-blockSetup
1. Add Plugin to Sanity Config
Add it as a plugin in sanity.config.ts (or .js):
import {defineConfig} from 'sanity'
import {heroBlockPlugin} from '@multidots/sanity-plugin-hero-block'
export default defineConfig({
// ... other config
plugins: [
heroBlockPlugin(),
// ... other plugins
],
})2. Add to Your Schema
Include the hero block in your page or document schemas:
// In your page schema
import {heroBlockType} from '@multidots/sanity-plugin-hero-block'
export const pageSchema = defineType({
name: 'page',
type: 'document',
fields: [
defineField({
name: "heroBlock",
type: "heroBlock",
}),
]
})3. Update GROQ Queries
Ensure your GROQ queries properly expand asset references:
*[_type == "page" && slug.current == $slug][0]{
content[]{
...,
_type == "heroBlock" => {
...,
"heroImage": heroImage{
...,
asset->{
_id,
url
}
},
heroVideoType,
heroVideoUrl,
"heroVideo": heroVideo{
...,
asset->{
_id,
url
}
}
}
}
}4. Frontend Component Usage
For a clean and maintainable frontend implementation, create a dedicated component wrapper first, then use it in your pages. This approach provides better code organization and reusability.
Create a Component Wrapper
First, create a HeroBlock.tsx component in your components directory:
// components/HeroBlock.tsx
import { HeroBlock } from "@multidots/sanity-plugin-hero-block";
import { urlFor } from "@/sanity/lib/image";
import { projectId, dataset } from "@/sanity/env";
interface HeroBlockComponentProps {
heroBlock: any; // Replace with your specific type
}
export default function HeroBlockComponent({ heroBlock }: HeroBlockComponentProps) {
// Return null if no hero block data is provided
if (!heroBlock) {
return null;
}
return (
<HeroBlock
heroBlock={heroBlock}
urlFor={urlFor} // For image asset processing
projectId={projectId} // For video asset URL construction
dataset={dataset} // For video asset URL construction
/>
);
}Use in Your Page Component
Then, import and use the component in your page:
// app/page.tsx or pages/[slug].tsx
import HeroBlockComponent from "@/components/HeroBlock";
export default function Page({ heroBlockData }) {
return (
<div>
{/* Hero Block Section */}
<HeroBlockComponent heroBlock={heroBlockData} />
{/* Other page content */}
<main>
{/* Your page content here */}
</main>
</div>
);
}Why This Approach?
🔧 Better Organization: Separating the hero block into its own component keeps your page components clean and focused.
♻️ Reusability: You can easily use the same hero block component across multiple pages without code duplication.
🛠️ Easier Maintenance: All hero block-specific logic and configuration stays in one place, making updates and debugging simpler.
🎯 Type Safety: You can add proper TypeScript interfaces specific to your data structure.
🔍 Error Handling: Built-in null checks prevent rendering errors when data is unavailable.
Schema Fields
Content Fields
headingText(string, required) - Main hero headingsubHeading(string, required) - Secondary text below heading
Call to Action
callToActionText(string, optional) - Button textcallToActionLink(url, optional) - Button destination URLopenInNewTab(boolean, optional) - Whether link opens in new tab
Background Settings
heroBgType(string) - Background type:"color"or"media"heroBgColor(color) - Background color (when type is "color")heroBgMedia(string) - Media type:"image"or"video"(when type is "media")heroImage(image) - Background image assetheroVideoType(string) - Video source type:"url"or"upload"(when media type is "video")heroVideoUrl(url) - Video URL for external videos like YouTube and Vimeo (when video type is "url")heroVideo(file) - Background video asset for uploaded files (when video type is "upload", accepts video/* formats)
Overlay Settings (for media backgrounds)
heroOverlayColor(color) - Overlay colorheroOverlayOpacity(number) - Overlay opacity (0-1)
Styling Options
contentAlignment(string) - Text alignment:"left","center", or"right"contentColor(color) - Text color for heading and subheadingbuttonBgColor(color) - Call-to-action button background colorbuttonTextColor(color) - Call-to-action button text color
Component API
Props
interface HeroBlockProps {
heroBlock: HeroBlockType;
urlFor?: (source: any) => ImageUrlBuilder; // Sanity image URL builder
projectId?: string; // Sanity project ID (for video URLs)
dataset?: string; // Sanity dataset (for video URLs)
}HeroBlockType Interface
interface HeroBlockType {
headingText: string;
subHeading: string;
callToAction?: {
callToActionText?: string;
callToActionLink?: string;
openInNewTab?: boolean;
};
heroBgType: 'color' | 'media';
heroBgColor?: { hex: string };
heroBgMedia?: 'image' | 'video';
heroImage?: {
asset: {
_ref: string;
_type: 'reference';
url?: string;
};
alt?: string;
};
heroVideoType?: 'url' | 'upload';
heroVideoUrl?: string;
heroVideo?: {
asset: {
_ref: string;
_type: 'reference';
url?: string;
};
};
heroOverlay?: {
heroOverlayColor?: { hex: string };
heroOverlayOpacity?: number;
};
contentAlignment: 'left' | 'center' | 'right';
contentColor?: { hex: string };
buttonBgColor?: { hex: string };
buttonTextColor?: { hex: string };
}Screenshots
Hero Block Backend Settings: https://share.cleanshot.com/n0MbHpMxh0lt3Mfzt0kl

Hero Block Style Settings: https://share.cleanshot.com/n1KxfK55SZfc1l5jQcV5

Hero Block Frontend Color BG: https://share.cleanshot.com/ZGcRbsgjcKtRMfNNxRjR

Hero Block Frontend Image BG: https://share.cleanshot.com/mwkHC2NJkgsqpGYMqMbt

Hero Block Frontend Video BG: https://share.cleanshot.com/1p6RgSfgVzcq61QTHcRl

Demo Video
https://share.cleanshot.com/wwGkZbDyG4mCsf4wSHcH
Troubleshooting
Video Not Playing
For Uploaded Videos:
- Ensure your GROQ query expands video assets:
asset->{ url } - Check that video files are in web-compatible formats (MP4, WebM, OGG)
- Verify
projectIdanddatasetprops are provided for fallback URL construction - Ensure
heroVideoTypeis set to"upload" - Mobile-specific: Check that videos are optimized for mobile bandwidth
- Autoplay issues: Mobile browsers may block autoplay - ensure videos are muted
For Video URLs (YouTube/Vimeo):
- Verify the video URL is publicly accessible
- Check that
heroVideoTypeis set to"url" - Ensure
heroVideoUrlcontains a valid URL - For YouTube: Use standard watch URLs (
https://www.youtube.com/watch?v=...) - For Vimeo: Use standard video URLs (
https://vimeo.com/...) - Some videos may not allow embedding - check video privacy settings
Images Not Loading
- Ensure
urlForhelper is passed to the component - Verify your GROQ query expands image assets:
asset->{ url } - Check that images are properly uploaded to Sanity
Development
This plugin uses @sanity/plugin-kit with default configuration for build & watch scripts.
Testing in Studio
See Testing a plugin in Sanity Studio for hot-reload development setup.
Building
npm run buildDevelopment with Watch
npm run watchLicense
MIT © Multidots
