# Sidebar 02

> A header, then a search field and category list beside a grid of posts whose featured post spans the full width.

URL: https://apogee.avaui.dev/docs/blog-sections/sidebar-02
Last updated: 2026-10-20

A header, then a search field and category list beside a grid of posts whose featured post spans the full width.

Last updated October 20, 2026

Live example: https://apogee.avaui.dev/examples/blog/sidebar-02

```astro
---
/**
 * Sidebar 02: A header, then a search field and category list beside a grid of posts whose featured post spans the full width.
 *
 * @block blog
 * @order 12
 */
import { Search as SearchIcon } from '@lucide/astro'
import Section from '@/components/apogee/Section/Section.astro'
import SectionHeader from '@/components/apogee/SectionHeader/SectionHeader.astro'
import PostCard from '@/components/apogee/PostCard/PostCard.astro'
import { plain } from '@/components/apogee/sections/_shared/spine.ts'
import { toCard, type BlogContent, type Post } from '@/components/apogee/sections/_shared/blog.ts'
import Grid from '@/components/apogee/Grid/Grid.astro'
import Tabs from '@/components/apogee/Tabs/Tabs.astro'
import Select from '@/components/apogee/Select/Select.astro'
import Pagination from '@/components/apogee/Pagination/Pagination.astro'
import Input from '@/components/apogee/Input/Input.astro'

const demoPosts: Post[] = [
  {
    title: 'Designing review sessions people look forward to',
    href: '#',
    excerpt: 'How to run critiques that sharpen the work instead of draining the room.',
    date: '2026-01-20',
    readingTime: '8 min read',
    image: { src: 'https://picsum.photos/seed/apogee-blog-1/960/640', alt: '', width: 960, height: 640 },
    category: { name: 'Design', href: '#' },
    author: { name: 'Ada Lovelace', href: '#' },
    tags: [{ name: 'Design', href: '#', color: 'primary' }, { name: 'Research', href: '#', color: 'neutral' }, { name: 'Process', href: '#', color: 'positive' }],
  },
  {
    title: 'Migrating to a typed component library',
    href: '#',
    excerpt: 'What changed when we moved two hundred screens onto one set of typed parts.',
    date: '2026-01-19',
    readingTime: '6 min read',
    image: { src: 'https://picsum.photos/seed/apogee-blog-2/960/640', alt: '', width: 960, height: 640 },
    category: { name: 'Engineering', href: '#' },
    author: { name: 'Alan Turing', href: '#' },
    tags: [{ name: 'Engineering', href: '#', color: 'primary' }, { name: 'Tooling', href: '#', color: 'neutral' }],
  },
  {
    title: 'Building your first internal API',
    href: '#',
    excerpt: 'The shape of a small API that teams can grow without rewriting.',
    date: '2026-01-18',
    readingTime: '7 min read',
    image: { src: 'https://picsum.photos/seed/apogee-blog-3/960/640', alt: '', width: 960, height: 640 },
    category: { name: 'Engineering', href: '#' },
    author: { name: 'Grace Hopper', href: '#' },
    tags: [{ name: 'Engineering', href: '#', color: 'primary' }, { name: 'APIs', href: '#', color: 'warning' }],
  },
  {
    title: 'A field guide to product discovery',
    href: '#',
    excerpt: 'Questions that turn a vague request into something you can build.',
    date: '2026-01-16',
    readingTime: '5 min read',
    image: { src: 'https://picsum.photos/seed/apogee-blog-4/960/640', alt: '', width: 960, height: 640 },
    category: { name: 'Product', href: '#' },
    author: { name: 'Katherine Johnson', href: '#' },
    tags: [{ name: 'Product', href: '#', color: 'primary' }, { name: 'Research', href: '#', color: 'neutral' }],
  },
  {
    title: 'Writing release notes people read',
    href: '#',
    excerpt: 'Lead with what changed for the reader, not what changed in the code.',
    date: '2026-01-15',
    readingTime: '4 min read',
    image: { src: 'https://picsum.photos/seed/apogee-blog-5/960/640', alt: '', width: 960, height: 640 },
    category: { name: 'Product', href: '#' },
    author: { name: 'Margaret Hamilton', href: '#' },
    tags: [{ name: 'Product', href: '#', color: 'primary' }, { name: 'Writing', href: '#', color: 'positive' }],
  },
  {
    title: 'Leadership lessons from a year of remote teams',
    href: '#',
    excerpt: 'Rituals, writing and trust: what held a distributed team together.',
    date: '2026-01-14',
    readingTime: '9 min read',
    image: { src: 'https://picsum.photos/seed/apogee-blog-6/960/640', alt: '', width: 960, height: 640 },
    category: { name: 'Leadership', href: '#' },
    author: { name: 'Alan Kay', href: '#' },
    tags: [{ name: 'Leadership', href: '#', color: 'primary' }, { name: 'Remote', href: '#', color: 'neutral' }],
  },
  {
    title: 'Accessible colour, measured',
    href: '#',
    excerpt: 'Why our build fails when a colour pair misses AA, and how we fixed the misses.',
    date: '2026-01-12',
    readingTime: '6 min read',
    image: { src: 'https://picsum.photos/seed/apogee-blog-7/960/640', alt: '', width: 960, height: 640 },
    category: { name: 'Design', href: '#' },
    author: { name: 'Hedy Lamarr', href: '#' },
    tags: [{ name: 'Design', href: '#', color: 'primary' }, { name: 'Accessibility', href: '#', color: 'positive' }],
  },
]
const demoCategories = [
  { label: 'View all', value: 'all', href: '#' },
  { label: 'Design', value: 'design', href: '#design' },
  { label: 'Product', value: 'product', href: '#product' },
  { label: 'Engineering', value: 'engineering', href: '#engineering' },
  { label: 'Leadership', value: 'leadership', href: '#leadership' },
  { label: 'Marketing', value: 'marketing', href: '#marketing' },
]

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

const {
  eyebrow = 'Our blog',
  heading = 'Resources and insights',
  description = 'The latest industry news, interviews, technologies and resources.',
  items = demoPosts,
  locale = Astro.currentLocale ?? 'en',
  categories = demoCategories,
} = Astro.props

---

<Section spacing="large">
  <SectionHeader eyebrow={eyebrow ?? undefined} heading={plain(heading)} description={description ?? undefined} headingLevel={1} class="mb-16" />
  <div class="grid gap-12 lg:grid-cols-[16rem_minmax(0,1fr)]">
    <aside class="flex flex-col gap-6 lg:sticky lg:top-[calc(var(--navbar-height)+2rem)] lg:self-start">
      <Input type="search" name="q" placeholder="Search" aria-label="Search posts"><SearchIcon slot="start" /></Input>
      {categories && <Select aria-label="Category" class="lg:hidden">
        {categories.map((c) => <option value={c.value}>{c.label}</option>)}
      </Select>}
      {categories && <Tabs label="Categories" value={categories[0]?.value} orientation="vertical" variant="borderless" tabs={categories} class="max-lg:hidden" />}
    </aside>
    <div>
      {items[0] && <PostCard post={toCard(items[0])} locale={locale} meta="badge" size="large" headingLevel={2} class="mb-12" />}
      <Grid as="ul" cols={{ base: 1, md: 2 }} gap={8} class="list-none p-0">
    {items.slice(1).map((post) => (
      <li><PostCard post={toCard(post)} locale={locale} meta="badge" headingLevel={2} class="h-full" /></li>
    ))}
  </Grid>
      <Pagination currentPage={1} totalPages={10} getHref={(p) => `?page=${p}`} labels class="mt-12 justify-between border-t border-neutral pt-5" />
    </div>
  </div>
</Section>
```

## Add

```sh
npx @ava-ui/apogee add blog/sidebar-02
```

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](https://apogee.avaui.dev/docs/blog-sections#copy-is-props).

This copies the block to `src/components/apogee/blocks/blog/` with everything it uses: Grid, Input, Pagination, PostCard, Section, SectionHeader, Select, Tabs. It opens a blog index page (its heading is the page’s `h1`). Swap the `posts` array for your content collection. Use **Copy code** above to paste it instead.

## Accessibility

-   Each post is one link: the title stretches over the card, and the author, category and tag links sit above it and stay clickable.
-   The decorative arrow and the images are hidden from screen readers (their alt is empty because the title already names the post).
-   The category row is a `<nav>` named “Categories”; the current category carries `aria-current="page"`.
-   The search field is named “Search posts”.
-   Pagination is a `<nav>` of links; the current page carries `aria-current="page"`.

## Related

[

PostCardOne article in a blog list; image, a top line, title, summary and a footer, as plain, a card or with an overlay.

](https://apogee.avaui.dev/docs/post-card)[

Blog listPost cards in a grid, or one featured post above the grid.

](https://apogee.avaui.dev/docs/sections/blog-list)
