Hero

A flexible opening section for landing pages, product pages, and documentation.

Hero is a content-led introductory block for product pages, documentation, and landing pages. It combines an optional eyebrow, primary heading, supporting description, actions, and optional media.

Variants and behaviour

The centered layout keeps attention on a concise message; the split layout makes room for media or a supporting panel beside the copy.

Customization

Compose action links through the actions array and place any product visual in the media snippet. Keep the textual props semantic and let the surrounding page control width and spacing.

Examples

Installation

Install Fractalsvelte, then import the block from the dedicated blocks entry point.

Install
pnpm add fractalsvelte
Import
<script lang="ts">
	import { Hero } from 'fractalsvelte/blocks';
</script>

Usage

Usage
<script lang="ts">
	import { Hero } from 'fractalsvelte/blocks';
</script>

<Hero title="Build with confidence" description="Composable Svelte building blocks." />

Props

PropTypeDefaultDescription
eyebrowstring-Small contextual label above the title.
titlestring-Primary page message.
descriptionstring-Supporting description.
actionsHeroAction[][]Optional action links.
layout'centered' | 'split''centered'Content alignment pattern.
mediaSnippet-Optional media region for split layout.

Source

Block source is published with the package and can be inspected here.

Hero.svelte
<script lang="ts">
	import type { Snippet } from 'svelte';
	interface Action { label: string; href: string; variant?: 'primary' | 'secondary'; }
	interface Props { eyebrow?: string; title: string; description: string; actions?: Action[]; layout?: 'centered' | 'split'; media?: Snippet; }
	let { eyebrow, title, description, actions = [], layout = 'centered', media }: Props = $props();
</script>
<section class="hero" data-layout={layout}>
	<div class="hero-copy box gap16">
		{#if eyebrow}<span class="text-sm col2">{eyebrow}</span>{/if}
		<h1>{title}</h1><p>{description}</p>
		{#if actions.length}<div class="row gap8 wrap">{#each actions as action (action.href)}<a class:btn-primary={action.variant !== 'secondary'} class:btn-secondary={action.variant === 'secondary'} href={action.href}>{action.label}</a>{/each}</div>{/if}
	</div>
	{#if media}<div class="hero-media">{@render media()}</div>{/if}
</section>
<style lang="sass">
	.hero
		background: var(--color10)
		border: 1px solid var(--border-tertiary)
		border-radius: 6px
		padding: 32px
		text-align: center
		transition: grid-template-columns 200ms ease, text-align 200ms ease
		p
			color: var(--text-secondary)
			font-size: var(--text-lg)
			margin: 0
	.hero[data-layout='split']
		display: grid
		gap: 32px
		grid-template-columns: repeat(2, minmax(0, 1fr))
		text-align: left
	.hero-media
		min-width: 0
	@media (max-width: 720px)
		.hero[data-layout='split']
			grid-template-columns: 1fr
	@media (prefers-reduced-motion: reduce)
		.hero
			transition: none
</style>