Gradient signup 01
A line and three link columns, then a large knot mark beside an underlined name and email signup with a consent note, and a row of small links, on a brand-colour gradient.
Last updated
---
/**
* Gradient signup 01: A line and three link columns, then a large knot mark beside an underlined name and email signup with a consent note, and a row of small links, on a brand-colour gradient.
*
* @block footers
* @order 57
*/
import Section from '@/components/apogee/Section/Section.astro'
import Link from '@/components/apogee/Link/Link.astro'
import { plain } from '@/components/apogee/sections/_shared/spine.ts'
import { type FooterContent } from '@/components/apogee/sections/_shared/footers.ts'
/** @composable */
interface Props extends FooterContent {}
const {
tagline = 'Modern haircare rooted in shared knowledge.',
newsletterDescription = 'Sign up to get 10% off your first order and hear first about new releases.',
submitLabel = 'Subscribe',
columns = [
{ heading: 'Shop', links: [{ label: 'Restoring shampoo', href: '#' }, { label: 'Restoring conditioner', href: '#' }, { label: 'Restoring serum', href: '#' }, { label: 'Restoring set', href: '#' }] },
{ heading: 'Learn more', links: [{ label: 'About us', href: '#' }, { label: 'Delivery and returns', href: '#' }, { label: 'Contact us', href: '#' }, { label: 'Questions', href: '#' }, { label: 'Privacy policy', href: '#' }] },
{ heading: 'Connect', links: [{ label: 'Photos', href: '#' }] },
],
copyright = '© Lumen Hair, 2026',
legal = [{ label: 'Privacy policy', href: '#' }, { label: 'Terms', href: '#' }, { label: 'Credits', href: '#' }],
} = Astro.props
---
<!-- The brand surface, deepening toward the top. -->
<Section as="footer" spacing="none" container={false} data-surface="primary" class="text-neutral" style="background: linear-gradient(to bottom, color-mix(in oklab, var(--background-page) 75%, black), var(--background-page))">
<div class="grid gap-12 px-gutter pt-12 lg:grid-cols-[1fr_2fr]">
{tagline && <p class="max-w-56 text-lg leading-snug">{plain(tagline)}</p>}
<div class="grid grid-cols-2 gap-8 sm:grid-cols-3">
{columns.map((c) => (
<nav aria-label={c.heading}>
<p class="text-xl">{c.heading}</p>
<ul class="mt-2 flex list-none flex-col gap-1 p-0 text-sm">{c.links.map((l) => <li><Link href={l.href} color="inherit" underline="hover">{l.label}</Link></li>)}</ul>
</nav>
))}
</div>
</div>
<div class="mt-32 grid gap-12 px-gutter pb-10 lg:grid-cols-[1fr_2fr] lg:items-end">
<!-- The knot: four rounded loops woven around a centre. -->
<svg viewBox="0 0 100 80" class="w-48 md:w-64" fill="none" stroke="currentColor" stroke-width="7" aria-hidden="true">
<rect x="6" y="6" width="44" height="34" rx="17" /><rect x="50" y="6" width="44" height="34" rx="17" />
<rect x="6" y="40" width="44" height="34" rx="17" /><rect x="50" y="40" width="44" height="34" rx="17" />
<path d="M30 22 70 58M70 22 30 58" />
</svg>
<div>
<form class="flex flex-col gap-4" onsubmit="return false">
{newsletterDescription && <p>{newsletterDescription}</p>}
<label class="sr-only" for="gradient-signup-name">Name</label>
<input id="gradient-signup-name" type="text" placeholder="Name" autocomplete="name" class="border-b border-neutral bg-transparent py-1.5 text-lg outline-none placeholder:text-neutral-faded focus-visible:border-current" />
<label class="sr-only" for="gradient-signup-email">Email</label>
<input id="gradient-signup-email" type="email" placeholder="Email" autocomplete="email" class="border-b border-neutral bg-transparent py-1.5 text-lg outline-none placeholder:text-neutral-faded focus-visible:border-current" />
<p class="text-xs">By subscribing you agree to receive marketing emails and accept our <Link href="#" color="inherit">privacy policy</Link>. You can unsubscribe at any time.</p>
<button type="submit" class="flex items-center gap-2 self-start"><span class="size-1.5 rounded-full bg-current" aria-hidden="true"></span>{submitLabel}</button>
</form>
<ul class="mt-8 grid list-none grid-cols-2 gap-2 p-0 text-xs sm:grid-cols-4">
{copyright && <li>{copyright}</li>}{legal && legal.map((l) => <li><Link href={l.href} color="inherit" underline="hover">{l.label}</Link></li>)}
</ul>
</div>
</div>
</Section>
Show codeHide code
---
/**
* Gradient signup 01: A line and three link columns, then a large knot mark beside an underlined name and email signup with a consent note, and a row of small links, on a brand-colour gradient.
*
* @block footers
* @order 57
*/
import Section from '@/components/apogee/Section/Section.astro'
import Link from '@/components/apogee/Link/Link.astro'
import { plain } from '@/components/apogee/sections/_shared/spine.ts'
import { type FooterContent } from '@/components/apogee/sections/_shared/footers.ts'
/** @composable */
interface Props extends FooterContent {}
const {
tagline = 'Modern haircare rooted in shared knowledge.',
newsletterDescription = 'Sign up to get 10% off your first order and hear first about new releases.',
submitLabel = 'Subscribe',
columns = [
{ heading: 'Shop', links: [{ label: 'Restoring shampoo', href: '#' }, { label: 'Restoring conditioner', href: '#' }, { label: 'Restoring serum', href: '#' }, { label: 'Restoring set', href: '#' }] },
{ heading: 'Learn more', links: [{ label: 'About us', href: '#' }, { label: 'Delivery and returns', href: '#' }, { label: 'Contact us', href: '#' }, { label: 'Questions', href: '#' }, { label: 'Privacy policy', href: '#' }] },
{ heading: 'Connect', links: [{ label: 'Photos', href: '#' }] },
],
copyright = '© Lumen Hair, 2026',
legal = [{ label: 'Privacy policy', href: '#' }, { label: 'Terms', href: '#' }, { label: 'Credits', href: '#' }],
} = Astro.props
---
<!-- The brand surface, deepening toward the top. -->
<Section as="footer" spacing="none" container={false} data-surface="primary" class="text-neutral" style="background: linear-gradient(to bottom, color-mix(in oklab, var(--background-page) 75%, black), var(--background-page))">
<div class="grid gap-12 px-gutter pt-12 lg:grid-cols-[1fr_2fr]">
{tagline && <p class="max-w-56 text-lg leading-snug">{plain(tagline)}</p>}
<div class="grid grid-cols-2 gap-8 sm:grid-cols-3">
{columns.map((c) => (
<nav aria-label={c.heading}>
<p class="text-xl">{c.heading}</p>
<ul class="mt-2 flex list-none flex-col gap-1 p-0 text-sm">{c.links.map((l) => <li><Link href={l.href} color="inherit" underline="hover">{l.label}</Link></li>)}</ul>
</nav>
))}
</div>
</div>
<div class="mt-32 grid gap-12 px-gutter pb-10 lg:grid-cols-[1fr_2fr] lg:items-end">
<!-- The knot: four rounded loops woven around a centre. -->
<svg viewBox="0 0 100 80" class="w-48 md:w-64" fill="none" stroke="currentColor" stroke-width="7" aria-hidden="true">
<rect x="6" y="6" width="44" height="34" rx="17" /><rect x="50" y="6" width="44" height="34" rx="17" />
<rect x="6" y="40" width="44" height="34" rx="17" /><rect x="50" y="40" width="44" height="34" rx="17" />
<path d="M30 22 70 58M70 22 30 58" />
</svg>
<div>
<form class="flex flex-col gap-4" onsubmit="return false">
{newsletterDescription && <p>{newsletterDescription}</p>}
<label class="sr-only" for="gradient-signup-name">Name</label>
<input id="gradient-signup-name" type="text" placeholder="Name" autocomplete="name" class="border-b border-neutral bg-transparent py-1.5 text-lg outline-none placeholder:text-neutral-faded focus-visible:border-current" />
<label class="sr-only" for="gradient-signup-email">Email</label>
<input id="gradient-signup-email" type="email" placeholder="Email" autocomplete="email" class="border-b border-neutral bg-transparent py-1.5 text-lg outline-none placeholder:text-neutral-faded focus-visible:border-current" />
<p class="text-xs">By subscribing you agree to receive marketing emails and accept our <Link href="#" color="inherit">privacy policy</Link>. You can unsubscribe at any time.</p>
<button type="submit" class="flex items-center gap-2 self-start"><span class="size-1.5 rounded-full bg-current" aria-hidden="true"></span>{submitLabel}</button>
</form>
<ul class="mt-8 grid list-none grid-cols-2 gap-2 p-0 text-xs sm:grid-cols-4">
{copyright && <li>{copyright}</li>}{legal && legal.map((l) => <li><Link href={l.href} color="inherit" underline="hover">{l.label}</Link></li>)}
</ul>
</div>
</div>
</Section>Add
npx @ava-ui/apogee add footers/gradient-signup-01
Every piece of copy is a prop, with the sample copy as its default. Pass yours, or null to hide a part; see copy is props.