Backers row 01
The logo, a line, social icons and a release-notes signup beside four link columns with external marks, then a row of backers and the copyright with small links.
Last updated
---
/**
* Backers row 01: The logo, a line, social icons and a release-notes signup beside four link columns with external marks, then a row of backers and the copyright with small links.
*
* @block footers
* @order 61
*/
import { ExternalLink, Hexagon, Atom, Sprout, Mountain } from '@lucide/astro'
import Section from '@/components/apogee/Section/Section.astro'
import Button from '@/components/apogee/Button/Button.astro'
import Link from '@/components/apogee/Link/Link.astro'
import { plain } from '@/components/apogee/sections/_shared/spine.ts'
import { socialIcons, type FooterContent, type FooterLink } from '@/components/apogee/sections/_shared/footers.ts'
/** @composable */
interface Props extends FooterContent {
/** Link groups; `external` adds an opens-elsewhere mark. @shape { heading: string, links: { label: string, href: string, external?: boolean }[] }[] @category content */
columns?: { heading: string; links: (FooterLink & { external?: boolean })[] }[]
/** Backer names; their marks cycle. @category content */
backers?: string[] | null
}
const backerIcons = [Hexagon, Atom, Sprout, Mountain]
const {
brand = 'rerise',
tagline = 'The data layer for physical AI, from collection to training.',
primaryAction = { label: 'Subscribe', href: '#' },
newsletterHeading = 'Subscribe to release notes',
newsletterDescription = 'Hear about new features as soon as they ship.',
columns = [
{ heading: 'Product', links: [{ label: 'Overview', href: '#' }, { label: 'SDK', href: '#' }, { label: 'Hub', href: '#' }, { label: 'Pricing', href: '#' }, { label: 'Changelog', href: '#', external: true }, { label: 'Web viewer', href: '#' }] },
{ heading: 'Resources', links: [{ label: 'Documentation', href: '#' }, { label: 'Quick start', href: '#' }, { label: 'Examples', href: '#' }, { label: 'API reference', href: '#' }, { label: 'Blog', href: '#' }] },
{ heading: 'Community', links: [{ label: 'Code', href: '#', external: true }, { label: 'Chat', href: '#', external: true }, { label: 'Updates', href: '#', external: true }, { label: 'Videos', href: '#', external: true }] },
{ heading: 'Company', links: [{ label: 'Careers', href: '#' }, { label: 'Team', href: '#' }, { label: 'Media kit', href: '#' }, { label: 'Contact us', href: '#', external: true }, { label: 'Privacy policy', href: '#' }, { label: 'Terms of service', href: '#' }] },
],
copyright = '© 2026 Rerise AB. All rights reserved.',
legal = [{ label: 'Privacy', href: '#' }, { label: 'Terms', href: '#' }, { label: 'Brand', href: '#' }, { label: 'Contact', href: '#' }],
social = [
{ label: 'Code', href: '#', icon: 'code' },
{ label: 'Community', href: '#', icon: 'users' },
{ label: 'Updates', href: '#', icon: 'at-sign' },
{ label: 'Videos', href: '#', icon: 'video' },
],
backers = ['Lumen', 'Quanta', 'Fieldwork', 'Northpeak'],
} = Astro.props
---
<Section as="footer" spacing="large">
<div class="grid gap-12 lg:grid-cols-[1.4fr_repeat(4,1fr)]">
<div class="flex flex-col gap-4">
<p class="text-2xl font-bold tracking-tight">{brand}</p>
{tagline && <p class="max-w-xs text-neutral-faded">{plain(tagline)}</p>}
{social && <ul class="flex list-none gap-3 p-0">{social.map((s) => { const Icon = socialIcons[s.icon]; return <li><Link href={s.href} color="neutral" underline="none" aria-label={s.label} class="text-neutral-faded hover:text-neutral"><Icon class="size-5" aria-hidden="true" /></Link></li> })}</ul>}
<div class="mt-8 flex flex-col items-start gap-2">
{newsletterHeading && <p class="font-medium">{newsletterHeading}</p>}
{newsletterDescription && <p class="max-w-xs text-neutral-faded">{newsletterDescription}</p>}
{primaryAction && <Button href={primaryAction.href} size="small">{primaryAction.label}</Button>}
</div>
</div>
{columns.map((c) => (
<nav aria-label={c.heading}>
<p class="font-medium">{c.heading}</p>
<ul class="mt-4 flex list-none flex-col gap-3 p-0">
{c.links.map((l) => <li><Link href={l.href} color="neutral" underline="hover" class="inline-flex items-center gap-1 text-neutral-faded hover:text-neutral">{l.label}{l.external && <ExternalLink class="size-3" aria-label="(opens elsewhere)" />}</Link></li>)}
</ul>
</nav>
))}
</div>
{backers && (
<div class="mt-12 flex flex-col items-center gap-6 border-y border-neutral-faded py-10">
<p class="text-sm text-neutral-faded">Backed by</p>
<ul class="flex list-none flex-wrap justify-center gap-x-10 gap-y-4 p-0">{backers.map((b, i) => { const Icon = backerIcons[i % backerIcons.length]!; return <li class="flex items-center gap-2 text-2xl font-bold"><Icon class="size-7" aria-hidden="true" />{b}</li> })}</ul>
</div>
)}
<div class="mt-6 flex flex-wrap justify-between gap-4 text-xs text-neutral-faded">
{copyright && <p>{copyright}</p>}
{legal && <ul class="flex list-none gap-5 p-0">{legal.map((l) => <li><Link href={l.href} color="neutral" underline="hover">{l.label}</Link></li>)}</ul>}
</div>
</Section>
Show codeHide code
---
/**
* Backers row 01: The logo, a line, social icons and a release-notes signup beside four link columns with external marks, then a row of backers and the copyright with small links.
*
* @block footers
* @order 61
*/
import { ExternalLink, Hexagon, Atom, Sprout, Mountain } from '@lucide/astro'
import Section from '@/components/apogee/Section/Section.astro'
import Button from '@/components/apogee/Button/Button.astro'
import Link from '@/components/apogee/Link/Link.astro'
import { plain } from '@/components/apogee/sections/_shared/spine.ts'
import { socialIcons, type FooterContent, type FooterLink } from '@/components/apogee/sections/_shared/footers.ts'
/** @composable */
interface Props extends FooterContent {
/** Link groups; `external` adds an opens-elsewhere mark. @shape { heading: string, links: { label: string, href: string, external?: boolean }[] }[] @category content */
columns?: { heading: string; links: (FooterLink & { external?: boolean })[] }[]
/** Backer names; their marks cycle. @category content */
backers?: string[] | null
}
const backerIcons = [Hexagon, Atom, Sprout, Mountain]
const {
brand = 'rerise',
tagline = 'The data layer for physical AI, from collection to training.',
primaryAction = { label: 'Subscribe', href: '#' },
newsletterHeading = 'Subscribe to release notes',
newsletterDescription = 'Hear about new features as soon as they ship.',
columns = [
{ heading: 'Product', links: [{ label: 'Overview', href: '#' }, { label: 'SDK', href: '#' }, { label: 'Hub', href: '#' }, { label: 'Pricing', href: '#' }, { label: 'Changelog', href: '#', external: true }, { label: 'Web viewer', href: '#' }] },
{ heading: 'Resources', links: [{ label: 'Documentation', href: '#' }, { label: 'Quick start', href: '#' }, { label: 'Examples', href: '#' }, { label: 'API reference', href: '#' }, { label: 'Blog', href: '#' }] },
{ heading: 'Community', links: [{ label: 'Code', href: '#', external: true }, { label: 'Chat', href: '#', external: true }, { label: 'Updates', href: '#', external: true }, { label: 'Videos', href: '#', external: true }] },
{ heading: 'Company', links: [{ label: 'Careers', href: '#' }, { label: 'Team', href: '#' }, { label: 'Media kit', href: '#' }, { label: 'Contact us', href: '#', external: true }, { label: 'Privacy policy', href: '#' }, { label: 'Terms of service', href: '#' }] },
],
copyright = '© 2026 Rerise AB. All rights reserved.',
legal = [{ label: 'Privacy', href: '#' }, { label: 'Terms', href: '#' }, { label: 'Brand', href: '#' }, { label: 'Contact', href: '#' }],
social = [
{ label: 'Code', href: '#', icon: 'code' },
{ label: 'Community', href: '#', icon: 'users' },
{ label: 'Updates', href: '#', icon: 'at-sign' },
{ label: 'Videos', href: '#', icon: 'video' },
],
backers = ['Lumen', 'Quanta', 'Fieldwork', 'Northpeak'],
} = Astro.props
---
<Section as="footer" spacing="large">
<div class="grid gap-12 lg:grid-cols-[1.4fr_repeat(4,1fr)]">
<div class="flex flex-col gap-4">
<p class="text-2xl font-bold tracking-tight">{brand}</p>
{tagline && <p class="max-w-xs text-neutral-faded">{plain(tagline)}</p>}
{social && <ul class="flex list-none gap-3 p-0">{social.map((s) => { const Icon = socialIcons[s.icon]; return <li><Link href={s.href} color="neutral" underline="none" aria-label={s.label} class="text-neutral-faded hover:text-neutral"><Icon class="size-5" aria-hidden="true" /></Link></li> })}</ul>}
<div class="mt-8 flex flex-col items-start gap-2">
{newsletterHeading && <p class="font-medium">{newsletterHeading}</p>}
{newsletterDescription && <p class="max-w-xs text-neutral-faded">{newsletterDescription}</p>}
{primaryAction && <Button href={primaryAction.href} size="small">{primaryAction.label}</Button>}
</div>
</div>
{columns.map((c) => (
<nav aria-label={c.heading}>
<p class="font-medium">{c.heading}</p>
<ul class="mt-4 flex list-none flex-col gap-3 p-0">
{c.links.map((l) => <li><Link href={l.href} color="neutral" underline="hover" class="inline-flex items-center gap-1 text-neutral-faded hover:text-neutral">{l.label}{l.external && <ExternalLink class="size-3" aria-label="(opens elsewhere)" />}</Link></li>)}
</ul>
</nav>
))}
</div>
{backers && (
<div class="mt-12 flex flex-col items-center gap-6 border-y border-neutral-faded py-10">
<p class="text-sm text-neutral-faded">Backed by</p>
<ul class="flex list-none flex-wrap justify-center gap-x-10 gap-y-4 p-0">{backers.map((b, i) => { const Icon = backerIcons[i % backerIcons.length]!; return <li class="flex items-center gap-2 text-2xl font-bold"><Icon class="size-7" aria-hidden="true" />{b}</li> })}</ul>
</div>
)}
<div class="mt-6 flex flex-wrap justify-between gap-4 text-xs text-neutral-faded">
{copyright && <p>{copyright}</p>}
{legal && <ul class="flex list-none gap-5 p-0">{legal.map((l) => <li><Link href={l.href} color="neutral" underline="hover">{l.label}</Link></li>)}</ul>}
</div>
</Section>Add
npx @ava-ui/apogee add footers/backers-row-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.