1 GitHub star = 1 new component.

Star the repo
Heroes

Hero Minimal Centered

Typography-first centered hero with announcement pill, highlighted headline word, two CTAs and trust signals.

herominimalcenteredtypography
Live Preview
New: 50 sections & 45 SVG charts

Build landing pages that feel expensive

Accessible, zero-dependency Astro components with a dark, refined aesthetic. Copy, paste, ship.

  • MIT licensed
  • WCAG AA
  • No runtime JS required

Usage

Copy and paste this code into your Astro page:

astro
---
import { HeroMinimalCentered } from 'astro-component-kit/sections';
---

<HeroMinimalCentered
  announcement="New: dark mode tokens"
  title="Build pages that *feel* expensive"
  subtitle="Accessible Astro components with zero runtime."
  primary={{ label: 'Get started', href: '/docs' }}
  secondary={{ label: 'GitHub', href: 'https://github.com' }}
  variant="grid"
/>
--- import { HeroMinimalCentered } from 'astro-component-kit/sections'; --- <HeroMinimalCentered announcement="New: dark mode tokens" title="Build pages that *feel* expensive" subtitle="Accessible Astro components with zero runtime." primary={{ label: 'Get started', href: '/docs' }} secondary={{ label: 'GitHub', href: 'https://github.com' }} variant="grid" />

Manual Installation

If you are not using the npm package, create a new file and paste the following code: src/components/sections/HeroMinimalCentered.astro:

astro
---
/**
 * HeroMinimalCentered — Typography-first centered hero with an announcement pill,
 * two CTAs and a row of trust signals. No imagery, loads instantly.
 *
 * @param {string} announcement - Text in the top pill (empty to hide).
 * @param {string} announcementHref - Link for the pill.
 * @param {string} title - Main headline. Wrap a word in *asterisks* to highlight it.
 * @param {string} subtitle - Supporting paragraph.
 * @param {{label: string, href: string}} primary - Primary CTA.
 * @param {{label: string, href: string}} secondary - Secondary CTA.
 * @param {string[]} trust - Short trust signals under the CTAs.
 * @param {string} variant - Background treatment (default|glow|grid).
 * @param {string} size - Vertical rhythm (sm|md|lg).
 * @param {string} className - Extra CSS class.
 */
interface Props {
  announcement?: string;
  announcementHref?: string;
  title?: string;
  subtitle?: string;
  primary?: { label: string; href: string };
  secondary?: { label: string; href: string };
  trust?: string[];
  variant?: 'default' | 'glow' | 'grid';
  size?: 'sm' | 'md' | 'lg';
  className?: string;
}

const {
  announcement = 'New: 50 sections & 45 SVG charts',
  announcementHref = '#',
  title = 'Build landing pages that *feel* expensive',
  subtitle = 'Accessible, zero-dependency Astro components with a dark, refined aesthetic. Copy, paste, ship.',
  primary = { label: 'Browse components', href: '#' },
  secondary = { label: 'Read the docs', href: '#' },
  trust = ['MIT licensed', 'WCAG AA', 'No runtime JS required'],
  variant = 'glow',
  size = 'lg',
  className = '',
} = Astro.props;

const id = `hmc-${Math.random().toString(36).slice(2, 8)}`;
const parts = title.split(/\*(.+?)\*/);
---

<section class={`hmc hmc--${variant} hmc--${size} ${className}`} aria-labelledby={id}>
  <div class="hmc__bg" aria-hidden="true"></div>
  <div class="hmc__inner">
    {announcement && (
      <a class="hmc__pill" href={announcementHref}>
        <span class="hmc__dot" aria-hidden="true"></span>
        {announcement}
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6" /></svg>
      </a>
    )}
    <h1 id={id} class="hmc__title">
      {parts.map((p, i) => (i % 2 ? <em>{p}</em> : p))}
    </h1>
    <p class="hmc__subtitle">{subtitle}</p>
    <div class="hmc__actions">
      <a class="hmc__btn hmc__btn--primary" href={primary.href}>{primary.label}</a>
      <a class="hmc__btn hmc__btn--ghost" href={secondary.href}>{secondary.label}</a>
    </div>
    {trust.length > 0 && (
      <ul class="hmc__trust">
        {trust.map((t) => (
          <li>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5" /></svg>
            {t}
          </li>
        ))}
      </ul>
    )}
  </div>
</section>

<style>
  .hmc {
    --hmc-py: 6rem;
    position: relative;
    overflow: hidden;
    padding: var(--hmc-py) var(--sp-6, 1.5rem);
    background: var(--c-bg, #050505);
    text-align: center;
  }
  .hmc--sm { --hmc-py: 4rem; }
  .hmc--lg { --hmc-py: 8rem; }
  .hmc__bg { position: absolute; inset: 0; pointer-events: none; }
  .hmc--glow .hmc__bg {
    background:
      radial-gradient(ellipse 60% 50% at 50% 0%, var(--c-primary-glow, color-mix(in srgb, var(--c-primary, #b8860b) 14%, transparent)), transparent 70%),
      radial-gradient(ellipse 40% 30% at 50% 100%, rgba(57, 135, 229, 0.08), transparent 70%);
  }
  .hmc--grid .hmc__bg {
    background-image:
      linear-gradient(rgb(var(--ink-rgb, 255 255 255) / 0.04) 1px, transparent 1px),
      linear-gradient(90deg, rgb(var(--ink-rgb, 255 255 255) / 0.04) 1px, transparent 1px);
    background-size: 48px 48px;
    mask-image: radial-gradient(ellipse 70% 60% at 50% 40%, #000, transparent);
  }
  .hmc__inner { position: relative; max-width: 820px; margin: 0 auto; }
  .hmc__pill {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 36px;
    padding: 0.35rem 0.9rem;
    border-radius: var(--r-full, 999px);
    border: 1px solid var(--c-border, rgb(var(--ink-rgb, 255 255 255) / 0.08));
    background: rgb(var(--ink-rgb, 255 255 255) / 0.03);
    color: var(--c-text-2, #a3a3a3);
    font-size: 0.8125rem;
    text-decoration: none;
    transition: border-color 0.2s ease, color 0.2s ease;
  }
  .hmc__pill:hover { border-color: rgb(var(--ink-rgb, 255 255 255) / 0.2); color: var(--c-text-1, #fff); }
  .hmc__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--c-primary-light, #d4a017); box-shadow: 0 0 10px var(--c-primary-light, #d4a017); }
  .hmc__title {
    margin: 1.75rem 0 1.25rem;
    font-size: clamp(2.5rem, 6vw, 4.5rem);
    font-weight: 800;
    line-height: 1.04;
    letter-spacing: -0.035em;
    color: var(--c-text-1, #fff);
    text-wrap: balance;
  }
  .hmc__title em {
    font-style: normal;
    background: linear-gradient(120deg, var(--c-accent, #fef3c7), var(--c-primary-light, #d4a017));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
  .hmc__subtitle {
    max-width: 600px;
    margin: 0 auto 2.25rem;
    font-size: clamp(1rem, 2vw, 1.1875rem);
    line-height: 1.6;
    color: var(--c-text-2, #a3a3a3);
  }
  .hmc__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; justify-content: center; }
  .hmc__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 48px;
    padding: 0 1.5rem;
    border-radius: var(--r-md, 12px);
    font-weight: 650;
    font-size: 0.9375rem;
    text-decoration: none;
    transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
  }
  .hmc__btn:hover { transform: translateY(-1px); }
  .hmc__btn:focus-visible, .hmc__pill:focus-visible { outline: 2px solid var(--c-primary-light, #d4a017); outline-offset: 3px; }
  .hmc__btn--primary { background: var(--c-primary-light, #d4a017); color: var(--c-on-primary, #0a0a0a); }
  .hmc__btn--primary:hover { background: var(--c-accent, #fef3c7); color: var(--c-on-primary, #0a0a0a); }
  .hmc__btn--ghost { border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.14); color: var(--c-text-1, #fff); }
  .hmc__btn--ghost:hover { border-color: rgb(var(--ink-rgb, 255 255 255) / 0.32); color: var(--c-text-1, #fff); }
  .hmc__trust {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.75rem 1.75rem;
    margin: 2.5rem 0 0;
    padding: 0;
    list-style: none;
    font-size: 0.875rem;
    color: var(--c-text-2, #a3a3a3);
  }
  .hmc__trust li { display: inline-flex; align-items: center; gap: 0.45rem; }
  .hmc__trust svg { color: var(--chart-pos, #34c38f); }
  @media (prefers-reduced-motion: reduce) { .hmc__btn { transition: none; } }
</style>
--- /** * HeroMinimalCentered — Typography-first centered hero with an announcement pill, * two CTAs and a row of trust signals. No imagery, loads instantly. * * @param {string} announcement - Text in the top pill (empty to hide). * @param {string} announcementHref - Link for the pill. * @param {string} title - Main headline. Wrap a word in *asterisks* to highlight it. * @param {string} subtitle - Supporting paragraph. * @param {{label: string, href: string}} primary - Primary CTA. * @param {{label: string, href: string}} secondary - Secondary CTA. * @param {string[]} trust - Short trust signals under the CTAs. * @param {string} variant - Background treatment (default|glow|grid). * @param {string} size - Vertical rhythm (sm|md|lg). * @param {string} className - Extra CSS class. */ interface Props { announcement?: string; announcementHref?: string; title?: string; subtitle?: string; primary?: { label: string; href: string }; secondary?: { label: string; href: string }; trust?: string[]; variant?: 'default' | 'glow' | 'grid'; size?: 'sm' | 'md' | 'lg'; className?: string; } const { announcement = 'New: 50 sections & 45 SVG charts', announcementHref = '#', title = 'Build landing pages that *feel* expensive', subtitle = 'Accessible, zero-dependency Astro components with a dark, refined aesthetic. Copy, paste, ship.', primary = { label: 'Browse components', href: '#' }, secondary = { label: 'Read the docs', href: '#' }, trust = ['MIT licensed', 'WCAG AA', 'No runtime JS required'], variant = 'glow', size = 'lg', className = '', } = Astro.props; const id = `hmc-${Math.random().toString(36).slice(2, 8)}`; const parts = title.split(/\*(.+?)\*/); --- <section class={`hmc hmc--${variant} hmc--${size} ${className}`} aria-labelledby={id}> <div class="hmc__bg" aria-hidden="true"></div> <div class="hmc__inner"> {announcement && ( <a class="hmc__pill" href={announcementHref}> <span class="hmc__dot" aria-hidden="true"></span> {announcement} <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6" /></svg> </a> )} <h1 id={id} class="hmc__title"> {parts.map((p, i) => (i % 2 ? <em>{p}</em> : p))} </h1> <p class="hmc__subtitle">{subtitle}</p> <div class="hmc__actions"> <a class="hmc__btn hmc__btn--primary" href={primary.href}>{primary.label}</a> <a class="hmc__btn hmc__btn--ghost" href={secondary.href}>{secondary.label}</a> </div> {trust.length > 0 && ( <ul class="hmc__trust"> {trust.map((t) => ( <li> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5" /></svg> {t} </li> ))} </ul> )} </div> </section> <style> .hmc { --hmc-py: 6rem; position: relative; overflow: hidden; padding: var(--hmc-py) var(--sp-6, 1.5rem); background: var(--c-bg, #050505); text-align: center; } .hmc--sm { --hmc-py: 4rem; } .hmc--lg { --hmc-py: 8rem; } .hmc__bg { position: absolute; inset: 0; pointer-events: none; } .hmc--glow .hmc__bg { background: radial-gradient(ellipse 60% 50% at 50% 0%, var(--c-primary-glow, color-mix(in srgb, var(--c-primary, #b8860b) 14%, transparent)), transparent 70%), radial-gradient(ellipse 40% 30% at 50% 100%, rgba(57, 135, 229, 0.08), transparent 70%); } .hmc--grid .hmc__bg { background-image: linear-gradient(rgb(var(--ink-rgb, 255 255 255) / 0.04) 1px, transparent 1px), linear-gradient(90deg, rgb(var(--ink-rgb, 255 255 255) / 0.04) 1px, transparent 1px); background-size: 48px 48px; mask-image: radial-gradient(ellipse 70% 60% at 50% 40%, #000, transparent); } .hmc__inner { position: relative; max-width: 820px; margin: 0 auto; } .hmc__pill { display: inline-flex; align-items: center; gap: 0.5rem; min-height: 36px; padding: 0.35rem 0.9rem; border-radius: var(--r-full, 999px); border: 1px solid var(--c-border, rgb(var(--ink-rgb, 255 255 255) / 0.08)); background: rgb(var(--ink-rgb, 255 255 255) / 0.03); color: var(--c-text-2, #a3a3a3); font-size: 0.8125rem; text-decoration: none; transition: border-color 0.2s ease, color 0.2s ease; } .hmc__pill:hover { border-color: rgb(var(--ink-rgb, 255 255 255) / 0.2); color: var(--c-text-1, #fff); } .hmc__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--c-primary-light, #d4a017); box-shadow: 0 0 10px var(--c-primary-light, #d4a017); } .hmc__title { margin: 1.75rem 0 1.25rem; font-size: clamp(2.5rem, 6vw, 4.5rem); font-weight: 800; line-height: 1.04; letter-spacing: -0.035em; color: var(--c-text-1, #fff); text-wrap: balance; } .hmc__title em { font-style: normal; background: linear-gradient(120deg, var(--c-accent, #fef3c7), var(--c-primary-light, #d4a017)); -webkit-background-clip: text; background-clip: text; color: transparent; } .hmc__subtitle { max-width: 600px; margin: 0 auto 2.25rem; font-size: clamp(1rem, 2vw, 1.1875rem); line-height: 1.6; color: var(--c-text-2, #a3a3a3); } .hmc__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; justify-content: center; } .hmc__btn { display: inline-flex; align-items: center; justify-content: center; min-height: 48px; padding: 0 1.5rem; border-radius: var(--r-md, 12px); font-weight: 650; font-size: 0.9375rem; text-decoration: none; transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease; } .hmc__btn:hover { transform: translateY(-1px); } .hmc__btn:focus-visible, .hmc__pill:focus-visible { outline: 2px solid var(--c-primary-light, #d4a017); outline-offset: 3px; } .hmc__btn--primary { background: var(--c-primary-light, #d4a017); color: var(--c-on-primary, #0a0a0a); } .hmc__btn--primary:hover { background: var(--c-accent, #fef3c7); color: var(--c-on-primary, #0a0a0a); } .hmc__btn--ghost { border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.14); color: var(--c-text-1, #fff); } .hmc__btn--ghost:hover { border-color: rgb(var(--ink-rgb, 255 255 255) / 0.32); color: var(--c-text-1, #fff); } .hmc__trust { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.75rem 1.75rem; margin: 2.5rem 0 0; padding: 0; list-style: none; font-size: 0.875rem; color: var(--c-text-2, #a3a3a3); } .hmc__trust li { display: inline-flex; align-items: center; gap: 0.45rem; } .hmc__trust svg { color: var(--chart-pos, #34c38f); } @media (prefers-reduced-motion: reduce) { .hmc__btn { transition: none; } } </style>