# Hero

> Part of mCSS (mcss.dev). Rendered page: https://mcss.dev/components/hero

The `Hero` component offers highly flexible, accessible hero sections for landing pages, product sites, and marketing. It supports full, split, and slideshow layouts; accepts image, video, gradient, or canvas backgrounds; provides overlay and text color controls; allows custom aspect ratios and content/media ordering; supports parallax, rounded corners, and a flush layout for the split variant; and is fully slot-based for custom content. ([Full size demo](/demos/hero).)

<Hero
  variant="full"
  height={40}
  media={{ type: "canvas", src: "/_js/triangles.js" }}
  overlayOpacity={0.3}
  overlayColor="--primary-950"
  roundCorners
  textColor="--base-0"
  class="mt-sm3"
>
  <h2 class="h1">Example Hero</h2>
  <p>This hero uses an animated canvas element as background.</p>
</Hero>

<div class="docs_oversizedTable">

| File                 | Description | Source      |
| -------------------- | ----------- | ----------- |
| `component.hero.css` | All hero styles (`.hero`) | [Github][1] |

</div>

[1]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/component.hero.css

#### Full layout (default)

The full layout spans the entire viewport with content centered over a background image, video, gradient, or canvas element. Use the `height` prop to control min-height (in `svh` units).

#### Split layout

The Split layout features an asymmetric split (e.g., `70/30`, `80/20`, etc.) with content on one side and media on the other. The media section fills the available space with an image or video, cropping as needed. The `ratio` prop defines the grid layout, `contentFirst` controls the DOM order of content and media, and `reversed` visually reverses their order (while the grid ratio remains unchanged).

#### Slideshow layout

The Slideshow layout features rotating content and background (same options available as for the Full layout) with pagination dots. Each slide can have its own media and content.

<Notice
  type="info"
  title="Multiple Heroes on a single page"
  class="mt-md3"
>
  Each `Hero` instance generates its own unique `id`, so multiple heroes on one
  page (including JavaScript-driven ones like slideshows) never cross-wire. Pass
  an explicit `id` prop only if you need a stable anchor to link to.
</Notice>

## HTML

### Elements

<div class="docs_oversizedTable">

| Class           | Description                                                                                       |
| --------------- | ------------------------------------------------------------------------------------------------- |
| `.hero_actions` | Wrapping button row inside the hero content, centered on the full and slideshow variants (the hero twin of `.section_actions`). |

</div>

### Custom properties

The following custom properties are available in [`settings.ui.css`](/docs/tokens#interface-tokens):

<div class="docs_oversizedTable">

| Property                             | Description                                     |
| ------------------------------------ | ----------------------------------------------- |
| `--hero-radius`                      | Border radius (on/off via `roundCorners` prop). |
| `--hero-content-padding`             | Padding for hero content area.                  |
| `--hero-actions-spacing`             | Space above the `.hero_actions` button row.     |
| `--hero-pagination-dot`              | Pagination dot size.                            |
| `--hero-pagination-dot-color`        | Pagination dot background color.                |
| `--hero-pagination-dot-active-color` | Active pagination dot color.                    |
| `--hero-pagination-opacity`          | Pagination dot default opacity.                 |

</div>

## Astro component

### General props

<div class="docs_oversizedTable">

| Prop           | Type    | Default | Description                                                   |
| -------------- | ------- | ------- | ------------------------------------------------------------- |
| `variant`      | string  | `full`  | Layout variant: Full, Split, and Slideshow.                   |
| `media`        | object  | —       | Image, video, gradient, or canvas background.                 |
| `roundCorners` | boolean | `false` | Whether the hero media has rounded corners.                   |
| `textColor`    | string  | —       | Text color (CSS variable or value).                           |
| `class`   | string  | —       | Additional CSS classes (see [helper classes](/docs/helpers)). |

</div>

### Split variant props

<div class="docs_oversizedTable">

| Prop           | Type    | Default | Description                                                                        |
| -------------- | ------- | ------- | ---------------------------------------------------------------------------------- |
| `ratio`        | string  | `62/38` | Split ratio, e.g. `70/30`, `40/60`, etc.                                           |
| `contentFirst` | boolean | `false` | If true, content appears before media in the DOM (left on desktop, top on mobile). |
| `reversed`     | boolean | `false` | Visually reverses the order set by `contentFirst` (does not change DOM order).     |
| `roundCorners` | boolean | `false` | If true, media has rounded corners.                                                |
| `flush`        | boolean | `false` | Removes outer padding from the content section, making text flush with the edge.   |

</div>

### Full and slideshow variant props

<div class="docs_oversizedTable">

| Prop                  | Type    | Default      | Description                          |
| --------------------- | ------- | ------------ | ------------------------------------ |
| `parallax`            | boolean | `false`      | Parallax effect (full variant only). |
| `height`              | number  | —            | Sets `min-height` in `svh` (0-100).  |
| `overlayOpacity`      | number  | `0`          | Overlay opacity.                     |
| `overlayColor`        | string  | `--base-950` | Overlay color (CSS var or value).    |
| `roundCorners`        | boolean | `false`      | If true, hero has rounded corners.   |
| `textColor`           | string  | —            | Text color (CSS var or value).       |
| `slideshowItems`      | array   | —            | Array of objects (see example).      |
| `slideshowAutoplay`   | boolean | `true`       | Slideshow autoplay.                  |
| `slideshowInterval`   | number  | `5000`       | Slideshow interval (ms).             |
| `slideshowTransition` | number  | `600`        | Slideshow transition speed (ms).     |

</div>

## Examples

<ul class="docs_examples">
  <li>
    ### Animated Canvas
    <Hero
      variant="full"
      height={50}
      media={{ type: "canvas", src: "/_js/triangles.js" }}
      overlayOpacity={0.3}
      overlayColor="--primary-950"
      roundCorners
      textColor="--base-0"
    >
      <h2 class="h1">Animated Canvas Hero</h2>
      <p>This hero uses an animated canvas element as background.</p>
      <a class="bt bt-lg bt-outline-white mt-md1" href="/demos/hero">Full Size Examples</a>
    </Hero>

```astro
---
import Hero from "../../components/Hero.astro";
---
<Hero
  variant="full"
  height={50}
  media={{ type: "canvas", src: "/_js/triangles.js" }}
  overlayOpacity={0.3}
  overlayColor="--primary-950"
  roundCorners
  textColor="--base-0"
>
  <h1>Animated Canvas Hero</h1>
  <p>Organic Delaunay triangles animated with primary colors.</p>
  <a class="bt bt-primary">Full Size Demo</a>
</Hero>
```

  </li>
  <li>
    ### Gradient background
    <Hero
      variant="full"
      height={50}
      media={{
        type: "gradient",
        src: "linear-gradient(120deg, #f0f 0%, #0ff 100%)",
      }}
      overlayOpacity={0.3}
      roundCorners
      textColor="--base-0"
    >
      <h2 class="h1">Gradient Background Hero</h2>
      <p>Showcase your brand with a beautiful, vibrant gradient background.</p>
      <a class="bt bt-lg bt-outline-white mt-md1" href="/demos/hero">Full Size Examples</a>
    </Hero>

```astro
---
import Hero from "../../components/Hero.astro";
---
<Hero
  variant="full"
  height={50}
  media={{
    type: "gradient",
    src: "linear-gradient(120deg, #f0f 0%, #0ff 100%)",
  }}
  overlayOpacity={0.3}
  roundCorners
  textColor="--base-0"
>
  <h1>Gradient Background Hero</h1>
  <p>Showcase your brand with a beautiful, vibrant gradient background.</p>
  <a class="bt bt-lg bt-outline-white mt-md1" href="/demos/hero">Full Size Examples</a>
</Hero>
```

  </li>
  <li>
    ### Background image
    <Hero
      variant="full"
      height={50}
      media={{ type: "image", src: triangle01, alt: "Background Example" }}
      overlayColor="--primary-950"
      overlayOpacity={0.4}
      roundCorners
      textColor="--base-0"
    >
      <h2 class="h1">Image Background Hero</h2>
      <p>This hero uses a static image as the background.</p>
      <a class="bt bt-lg bt-outline-white mt-md1" href="/demos/hero">Full Size Examples</a>
    </Hero>

```astro
---
import Hero from "../../components/Hero.astro";
import triangle01 from "../../assets/images/triangles.svg";
---
<Hero
  variant="full"
  height={50}
  media={{ type: "image", src: triangle01, alt: "Background Example" }}
  overlayColor="--primary-950"
  overlayOpacity={0.4}
  roundCorners
  textColor="--base-0"
>
  <h1>Image Background Hero</h1>
  <p>This hero uses a static image as the background.</p>
  <a class="bt bt-lg bt-outline-white mt-md1" href="/demos/hero">Full Size Examples</a>
</Hero>
```

  </li>
  <li>
  ### Slideshow
  <Hero
    id="heroSlideshow"
    variant="slideshow"
    height={40}
    overlayOpacity={0.6}
    overlayColor="--primary-950"
    textColor="--base-0"
    roundCorners
    slideshowInterval={4000}
    slideshowTransition={600}
    slideshowItems={[
      {
        media: { type: 'image', src: triangle01, alt: 'Triangle 01' },
      },
      {
        media: { type: 'image', src: triangle02, alt: 'Triangle 02' },
      },
      {
        media: { type: 'image', src: triangle03, alt: 'Triangle 03' },
      },
    ]}>
    <ul>
      <li>
        <h2 class="h1">First Slide</h2>
        <p>This is the first slide of the slideshow.</p>
      </li>
      <li>
        <h2 class="h1">Second Slide</h2>
        <p>This is the second slide of the slideshow.</p>
      </li>
      <li>
        <h2 class="h1">Third Slide</h2>
        <p>This is the third slide of the slideshow.</p>
      </li>
    </ul>
  </Hero>

```astro
---
import Hero from "../../components/Hero.astro";
import triangle01 from "../../assets/images/triangle-01.svg";
import triangle02 from "../../assets/images/triangle-02.svg";
import triangle03 from "../../assets/images/triangle-03.svg";
---
<Hero
  id="heroSlideshow"
  variant="slideshow"
  height={40}
  overlayOpacity={0.6}
  overlayColor="--primary-950"
  textColor="--base-0"
  roundCorners
  slideshowInterval={4000}
  slideshowTransition={600}
  slideshowItems={[
    {
      media: { type: 'image', src: triangle01, alt: 'Triangle 01' },
    },
    {
      media: { type: 'image', src: triangle02, alt: 'Triangle 02' },
    },
    {
      media: { type: 'image', src: triangle03, alt: 'Triangle 03' },
    },
  ]}>
  <ul>
    <li>
      <h1>First Slide</h1>
      <p>This is the first slide of the slideshow.</p>
    </li>
    <li>
      <h1>Second Slide</h1>
      <p>This is the second slide of the slideshow.</p>
    </li>
    <li>
      <h1>Third Slide</h1>
      <p>This is the third slide of the slideshow.</p>
    </li>
  </ul>
</Hero>
```

  </li>
  <li>
    ### Default split
    <Hero
      variant="split"
      roundCorners
      media={{ type: "image", src: triangle01, alt: "Split Example" }}
    >
      <h2 class="h1">Split Hero (Content Right)</h2>
      <p>Default split with content on the right and media on the left.</p>
    </Hero>

```astro
---
import Hero from "../../components/Hero.astro";
import triangle01 from "../../assets/images/triangles.svg";
---
<Hero
  variant="split"
  roundCorners
  media={{ type: "image", src: triangle01, alt: "Split Example" }}
>
  <h1>Split Hero (Content Right)</h1>
  <p>Default split with content on the right and media on the left.</p>
</Hero>
```

  </li>
  <li>
    ### Content first split
    <Hero
      variant="split"
      ratio="62/38"
      contentFirst
      flush
      roundCorners
      media={{ type: "image", src: triangle01, alt: "Split Example" }}
    >
      <h2 class="h1">Split Hero (Content First)</h2>
      <p>This example uses the <code>contentFirst</code> prop to place content before media in the DOM (left on desktop, top on mobile).</p>
    </Hero>

```astro
---
import Hero from "../../components/Hero.astro";
import triangle01 from "../../assets/images/triangles.svg";
---
<Hero
  variant="split"
  ratio="62/38"
  contentFirst
  flush
  roundCorners
  media={{ type: "image", src: triangle01, alt: "Split Example" }}
>
  <h1>Split Hero (Content First)</h1>
  <p>This example uses the <code>contentFirst</code> prop to place content before media in the DOM (left on desktop, top on mobile).</p>
</Hero>
```

  </li>
  <li>
    ### Content first reversed split
    <Hero
      variant="split"
      ratio="62/38"
      reversed
      flush
      roundCorners
      media={{ type: "image", src: triangle01, alt: "Split Example" }}
    >
      <h2 class="h1">Split Hero (Reversed)</h2>
      <p>This example uses the <code>reversed</code> prop to visually flip the order of content and media, without changing their DOM order. The <code>flush</code> prop removes left padding.</p>
    </Hero>

```astro
---
import Hero from "../../components/Hero.astro";
import triangle01 from "../../assets/images/triangles.svg";
---
<Hero
  variant="split"
  ratio="60/40"
  reversed
  flush
  roundCorners
  media={{ type: "image", src: triangle01, alt: "Split Example" }}
>
  <h1>Split Hero (Reversed)</h1>
  <p>This example uses the <code>reversed</code> prop to visually flip the order of content and media, without changing their DOM order. The <code>flush</code> prop removes left padding.</p>
</Hero>
```

  </li>
</ul>
