Joint session with Vercel: How to build intelligent storefronts (May 15th) →

Sanity Hero Block Plugin

Hero block plugin designed specifically for **Sanity Studio v3/v4** that enables content creators to build visually striking landing page headers. Create engaging hero sections with dynamic backgrounds, text content sections, call-to-action buttons, and overlay effects - all managed through Sanity's content management interface.

By Multidots

Install command

npm i @multidots/sanity-plugin-hero-block

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-block

Setup

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 heading
  • subHeading (string, required) - Secondary text below heading

Call to Action

  • callToActionText (string, optional) - Button text
  • callToActionLink (url, optional) - Button destination URL
  • openInNewTab (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 asset
  • heroVideoType (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 color
  • heroOverlayOpacity (number) - Overlay opacity (0-1)

Styling Options

  • contentAlignment (string) - Text alignment: "left", "center", or "right"
  • contentColor (color) - Text color for heading and subheading
  • buttonBgColor (color) - Call-to-action button background color
  • buttonTextColor (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:

  1. Ensure your GROQ query expands video assets: asset->{ url }
  2. Check that video files are in web-compatible formats (MP4, WebM, OGG)
  3. Verify projectId and dataset props are provided for fallback URL construction
  4. Ensure heroVideoType is set to "upload"
  5. Mobile-specific: Check that videos are optimized for mobile bandwidth
  6. Autoplay issues: Mobile browsers may block autoplay - ensure videos are muted

For Video URLs (YouTube/Vimeo):

  1. Verify the video URL is publicly accessible
  2. Check that heroVideoType is set to "url"
  3. Ensure heroVideoUrl contains a valid URL
  4. For YouTube: Use standard watch URLs (https://www.youtube.com/watch?v=...)
  5. For Vimeo: Use standard video URLs (https://vimeo.com/...)
  6. Some videos may not allow embedding - check video privacy settings

Images Not Loading

  1. Ensure urlFor helper is passed to the component
  2. Verify your GROQ query expands image assets: asset->{ url }
  3. 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 build

Development with Watch

npm run watch

License

MIT Ā© Multidots

Related contributions