A policy page: a centred header with legal and plain-language tabs over the policy text.

Last updated

Open block
Show code
---
/**
 * Simple: A policy page: a centred header with legal and plain-language tabs over the policy text.
 *
 * @block content
 * @order 12
 */
import Section from '@/components/apogee/Section/Section.astro'
import Prose from '@/components/apogee/Prose/Prose.astro'
import Heading from '@/components/apogee/Heading/Heading.astro'
import Tabs from '@/components/apogee/Tabs/Tabs.astro'
import { plain } from '@/components/apogee/sections/_shared/spine.ts'
import type { ContentContent } from '@/components/apogee/sections/_shared/content.ts'
import { formatDate } from '@/components/apogee/sections/_shared/date.ts'

/** @composable */
interface Props extends ContentContent {}

const {
  heading = 'Privacy policy',
  description = 'Your privacy is important to us. We respect it with regard to any information we may collect while you use our website.',
  date = '2026-01-20',
} = Astro.props
---

<article>
  <Section spacing="large" containerWidth="small">
    <header class="mb-12 flex flex-col items-center gap-4 text-center">
      <p class="text-sm font-semibold text-primary">Current as of <time datetime={date}>{formatDate(date, 'en-GB', 'short')}</time></p>
      <Heading as="h1" size="h1">{plain(heading)}</Heading>
      {description && <p class="text-lg text-neutral-faded">{description}</p>}
    </header>
    <Tabs tabs={[{ label: 'Legal version', value: 'legal' }, { label: 'Plain version', value: 'plain' }]} variant="pills-raised" class="[&_.apogee-tabs-list]:mx-auto [&_.apogee-tabs-list]:w-fit [&_.apogee-tabs-list]:max-w-full">
      <div slot="panel-legal" class="mt-8">
        <Prose>
          <p>This policy explains what information we collect when you use our website and services, how we use it, and the choices you have.</p>
          <h2>What information do we collect?</h2>
          <p>We collect the information you give us (your name and email when you sign up) and the information your browser sends when you visit (pages viewed, approximate location and device type).</p>
          <h2>How do we use your information?</h2>
          <p>To provide the service, to answer your messages and, with your consent, to send you news. We never sell your information.</p>
          <h3>Do we use cookies?</h3>
          <p>Only those needed for the site to work, and, if you allow them, a privacy-friendly analytics cookie.</p>
          <h2>How long do we keep your information?</h2>
          <p>As long as your account is open, and for up to 30 days after you close it.</p>
          <h2>How can you contact us?</h2>
          <p>Write to privacy@example.com and we will answer within 30 days.</p>
        </Prose>
      </div>
      <div slot="panel-plain" class="mt-8">
        <Prose>
          <p class="lead">The short version.</p>
          <ul>
            <li>We collect your name and email when you sign up, and basic visit data.</li>
            <li>We use it to run the service and answer you. We never sell it.</li>
            <li>We only set the cookies the site needs, unless you allow analytics.</li>
            <li>Close your account and we delete your data within 30 days.</li>
          </ul>
        </Prose>
      </div>
    </Tabs>
  </Section>
</article>

Add

npx @ava-ui/apogee add content/simple

This copies the block to src/components/apogee/blocks/content/ with everything it uses: Heading, Prose, Section, Tabs. 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.

Accessibility

  • The heading is an h2 by default, so the block slots into a page under its h1; item titles are one level down.
  • The department tabs are a tab list with one panel each; without JS every panel shows, one after another.