# Hero 06

> A split product hero with dual CTA, a compact logo row, and the Spot 01 illustration.

A shadcn/ui block from the [@flx](https://ui.flexnative.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/flx/hero-06).

- Page, with a live preview: https://shadcn.exchange/r/flx/hero-06
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/flx/hero-06-light-14da8451bee46e3a.png
- Registry item: https://ui.flexnative.com/r/hero-06.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://ui.flexnative.com/r/hero-06.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `motion`, `react-wrap-balancer`
- Registry items: `@flx/cta`, `@flx/spot-01`

## Files

### `registry/blocks/hero/hero-06/hero-06.tsx`

```tsx
'use client'

import * as React from 'react'
import { motion, useReducedMotion, type Variants } from 'motion/react'
import Balancer from 'react-wrap-balancer'

import type { CtaProps } from '../../shared/cta'
import { Cta } from '../../shared/cta'
import { Spot01 } from '../../../illustrations/spot/spot-01'

export interface Hero06Props {
  title: string
  highlight?: string
  description: string
  animation?: 'none' | 'subtle'
  primaryCTA: CtaProps
  secondaryCTA?: CtaProps
  logos: string[]
  logosLabel?: string
}

const container: Variants = {
  hidden: {},
  visible: { transition: { staggerChildren: 0.1, delayChildren: 0.05 } },
}

const item: Variants = {
  hidden: { opacity: 0, y: 12, filter: 'blur(6px)' },
  visible: {
    opacity: 1,
    y: 0,
    filter: 'blur(0px)',
    transition: { duration: 0.5, ease: [0.22, 1, 0.36, 1] },
  },
}

function Reveal({
  active,
  className,
  children,
}: Readonly<{
  active: boolean
  className?: string
  children: React.ReactNode
}>) {
  if (!active) return <div className={className}>{children}</div>

  return (
    <motion.div variants={item} className={className}>
      {children}
    </motion.div>
  )
}

export function Hero06({
  title,
  highlight,
  description,
  animation = 'none',
  primaryCTA,
  secondaryCTA,
  logos = [],
  logosLabel,
}: Readonly<Hero06Props>) {
  const reduce = useReducedMotion()
  const animate = animation === 'subtle' && !reduce

  const titleElement = title && (
    <h1 className="text-foreground font-serif text-2xl font-normal tracking-tight text-balance sm:text-3xl md:text-4xl">
      <Balancer>{title}</Balancer>
      {highlight && (
        <>
          {' '}
          <span className="text-muted-foreground">{highlight}</span>
        </>
      )}
    </h1>
  )

  const descriptionElement = description && (
    <p className="text-muted-foreground max-w-md text-base sm:text-lg">
      <Balancer>{description}</Balancer>
    </p>
  )

  const ctasElement = (primaryCTA?.ctaEnabled || secondaryCTA?.ctaEnabled) && (
    <div className="flex w-full flex-col gap-3 sm:w-auto sm:flex-row">
      {primaryCTA && <Cta cta={primaryCTA} className="w-full sm:w-fit" />}
      {secondaryCTA && <Cta cta={secondaryCTA} className="w-full sm:w-fit" />}
    </div>
  )

  const logosElement = (
    <div className="flex flex-col gap-3">
      {logosLabel && logos.length > 0 && (
        <p className="text-muted-foreground/80 text-xs tracking-wide uppercase">
          {logosLabel}
        </p>
      )}
      {logos.length > 0 && (
        <div className="flex flex-wrap items-center gap-x-6 gap-y-3">
          {logos.map((logo, index) => (
            <span
              key={index}
              className="text-muted-foreground/60 text-sm font-semibold tracking-tight"
            >
              {logo}
            </span>
          ))}
        </div>
      )}
    </div>
  )

  return (
    <section className="bg-background relative w-full overflow-hidden">
      <div
        aria-hidden
        className="pointer-events-none absolute inset-0 -z-10 opacity-70 dark:opacity-40"
        style={{
          backgroundImage:
            'linear-gradient(to right, var(--border) 1px, transparent 1px), linear-gradient(to bottom, var(--border) 1px, transparent 1px)',
          backgroundSize: '64px 64px',
          maskImage:
            'radial-gradient(ellipse 80% 60% at 75% 25%, black 30%, transparent 72%)',
          WebkitMaskImage:
            'radial-gradient(ellipse 80% 60% at 75% 25%, black 30%, transparent 72%)',
        }}
      />

      <motion.div
        className="mx-auto grid max-w-6xl grid-cols-1 items-center gap-12 px-6 py-16 sm:py-24 lg:grid-cols-2 lg:gap-16"
        variants={animate ? container : undefined}
        initial={animate ? 'hidden' : false}
        whileInView={animate ? 'visible' : undefined}
        viewport={{ once: true, margin: '-80px' }}
      >
        <div className="flex flex-col items-start gap-8">
          <Reveal active={animate} className="flex flex-col items-start gap-5">
            {titleElement}
            {descriptionElement}
          </Reveal>

          <Reveal active={animate}>{ctasElement}</Reveal>

          <Reveal active={animate}>{logosElement}</Reveal>
        </div>

        <Reveal active={animate} className="w-full">
          <Spot01 size="lg" />
        </Reveal>
      </motion.div>
    </section>
  )
}
```

### `registry/blocks/hero/hero-06/hero-06-example.tsx`

```tsx
import { Hero06, type Hero06Props } from './hero-06'

export const values = {
  title: 'Ship your best work,',
  highlight: 'without the busywork.',
  description:
    'One workspace to plan, build, and launch. No context switching, no clutter.',
  animation: 'subtle',
  primaryCTA: {
    ctaEnabled: true,
    text: 'Start for free',
    link: '',
    variant: 'default',
  },
  secondaryCTA: {
    ctaEnabled: true,
    text: 'Book a demo',
    link: '',
    variant: 'outline',
  },
  logosLabel: 'Trusted by fast-moving teams',
  logos: ['Acme', 'Globex', 'Initech', 'Umbrella'],
} satisfies Hero06Props

export function Hero06Example() {
  return <Hero06 {...values} />
}
```
