# Hero Statement

> Centred headline and actions above a wide media panel.

- **Slug:** `hero-statement`
- **Kind:** section · **Category:** Hero
- **Source:** original to Viewership UI
- **Docs page:** https://viewership.ai/ui/components/hero-statement
- **All files in one bundle:** https://viewership.ai/ui/components/hero-statement.bundle.txt
- **Structured JSON:** https://viewership.ai/ui/components/hero-statement.json

## Install

1. Import the foundation tokens once (download: https://viewership.ai/ui/raw/foundation.css.txt):

```astro
---
// src/layouts/Layout.astro
import "../styles/foundation.css";
---
```

2. Copy this file into `src/components/viewership/hero-statement/`:

   - `HeroStatement.astro` (raw: https://viewership.ai/ui/raw/hero-statement/HeroStatement.astro.txt)

3. Copy its registry dependencies, each into its own sibling folder under `src/components/viewership/`:

   - `button`: `Button.astro` (docs: https://viewership.ai/ui/components/button.md)

npm packages: none.

## Usage

```astro
---
import HeroStatement from "../components/viewership/hero-statement/HeroStatement.astro";
---

<HeroStatement />
```

## Example

The gallery demo, verbatim. Use the import path from Usage instead of `./`.

```astro
---
import HeroStatement from "./HeroStatement.astro";
---

<HeroStatement
  title="Gear for the"
  accent="long way round."
  body="Tents, packs and layers cut in small batches, repaired for life and shipped from one warehouse in Duluth."
  primary={{ label: "Shop the range", href: "#" }}
  secondary={{ label: "Read the repair promise", href: "#" }}
>
  <img slot="media" src="/ui/demo/ridgeline.webp" alt="Layered mountain ridges at dusk" width="1600" height="1000" loading="lazy" />
</HeroStatement>
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `title` | `string` |  | Headline. |
| `accent` | `string` |  | Closing words of the headline, drawn in the theme's accent style (<em>). |
| `body` | `string` |  | Supporting paragraph. |
| `primary` | `{ label: string; href: string }` |  | Main call to action. |
| `secondary` | `{ label: string; href: string }` |  | Quieter second action. |
| `as` | `"h1" \| "h2"` | `"h1"` | Heading element. |
| `slot: media` | `slot` |  | Image, video or rendered visual, cropped to 16:7. |

## Source

### `src/components/viewership/hero-statement/HeroStatement.astro`

```astro
---
/**
 * HeroStatement: centred headline and actions over a wide media panel.
 *
 * Media goes in the `media` slot (image, video, rendered visual). The section
 * responds to its own width, and its look follows the --vs-* tokens or a
 * theme preset.
 *
 * @example
 * <HeroStatement title="Gear for the" accent="long way round." primary={{ label: "Shop", href: "/shop" }}>
 *   <img slot="media" src="/hero.webp" alt="" />
 * </HeroStatement>
 */
import Button from "../button/Button.astro";

interface Cta {
  label: string;
  href: string;
}
interface Props {
  title: string;
  /** Closing words of the headline, drawn in the theme's accent style. */
  accent?: string;
  body?: string;
  primary?: Cta;
  secondary?: Cta;
  /** Heading element. Use "h2" when the page already has an h1. */
  as?: "h1" | "h2";
  class?: string;
}

const { title, accent, body, primary, secondary, as: Heading = "h1", class: className } = Astro.props;
---

<section class:list={["vs-hero-statement", className]}>
  <div class="vs-hero-statement__inner">
    <Heading class="vs-display vs-hero-statement__title">{title}{accent && <> <em>{accent}</em></>}</Heading>
    {body && <p class="vs-hero-statement__body">{body}</p>}
    {
      (primary || secondary) && (
        <div class="vs-hero-statement__actions">
          {primary && <Button href={primary.href} variant="primary">{primary.label}</Button>}
          {secondary && <Button href={secondary.href} variant="secondary">{secondary.label}</Button>}
        </div>
      )
    }
    {
      Astro.slots.has("media") && (
        <div class="vs-hero-statement__media">
          <slot name="media" />
        </div>
      )
    }
  </div>
</section>

<style>
  .vs-hero-statement {
    container-type: inline-size;
    background: var(--vs-page);
    color: var(--vs-ink);
    font-family: var(--vs-font-sans);
    font-stretch: var(--vs-font-stretch);
    text-align: center;
  }
  .vs-hero-statement__inner {
    max-width: var(--vs-container);
    margin-inline: auto;
    padding: var(--vs-section-y) var(--vs-gutter);
  }
  .vs-hero-statement__title {
    font-size: clamp(2.5rem, 10cqi, 6.75rem);
  }
  .vs-hero-statement__body {
    max-width: 34rem;
    margin: 1.5rem auto 0;
    font-size: 1.0625rem;
    line-height: 1.55;
    color: var(--vs-ink-2);
  }
  .vs-hero-statement__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 12px;
    margin-top: 2rem;
  }
  .vs-hero-statement__media {
    margin-top: clamp(40px, 7cqi, 72px);
    aspect-ratio: 16 / 7;
    overflow: hidden;
    border: var(--vs-border-w) solid var(--vs-line);
    border-radius: var(--vs-radius-window);
    background: var(--vs-canvas);
    box-shadow: var(--vs-pop-shadow, none);
  }
  .vs-hero-statement__media :global(:is(img, video)) {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
</style>
```
