# Blog Search Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Add a light, in-page keyword/topic filter to `/blog` that narrows the year-grouped archive as the reader types. **Architecture:** Tiny client-side filter implemented as `data-search` attributes on each row + featured block. A small inline vanilla-JS script in a new `BlogSearch.astro` component tokenizes the query, toggles `.is-hidden` on rows whose `data-search` doesn't contain every token, hides empty year heads, and toggles a no-results message. No JSON index, no fetch, no React island, no new dependencies. **Tech Stack:** Astro 5 content collections, Astro components (`.astro`), scoped CSS, vanilla JS. **Source spec:** `docs/superpowers/specs/2026-06-01-blog-search-design.md` **Verification note:** This repo has no automated test harness, and the spec deliberately doesn't add one. Each task ends with a manual verification step using the Astro dev server (`npm run dev` → http://localhost:4321/blog) and/or grep/curl against the rendered HTML. Confirm the verification passes before committing. --- ## File map | File | Action | Responsibility | |---|---|---| | `src/components/molecules/PostRow.astro` | modify | Accept `searchText` prop, emit `data-search` on root anchor | | `src/components/molecules/YearHead.astro` | modify | Emit `data-year-head` on root | | `src/pages/blog/index.astro` | modify | Build `searchText` per post; wire to `PostRow` + featured `
`; render `` and the empty-state `

`; add `.is-hidden` rule | | `src/components/molecules/BlogSearch.astro` | create | Input, styles, and the filter script (including keyboard shortcuts) | --- ## Task 1: `PostRow` accepts and emits `data-search` **Files:** - Modify: `src/components/molecules/PostRow.astro` - [ ] **Step 1: Add the `searchText` prop and emit it on the root anchor** Edit `src/components/molecules/PostRow.astro` — change the frontmatter and the `` tag: ```astro --- interface Props { date: string; title: string; href: string; deck?: string; tag?: string; searchText: string; } const { date, title, href, deck, tag, searchText } = Astro.props; --- {date} {title} {deck && {deck}} {tag && {tag}} ``` Leave the ` ``` - [ ] **Step 2: Mount the component and add the empty-state element + `.is-hidden` rule in the blog index** In `src/pages/blog/index.astro`: (a) Inside the `` body, place `` between the closing `` of `.masthead` and the `{featured && (...)}` block. The resulting structure should look like: ```astro

{/* ...unchanged... */}
{ featured && (
{/* ...unchanged... */}
) } ``` (b) After the closing `` of `.archive`, add the empty-state paragraph: ```astro ``` (c) Inside the existing ``): ```css .is-hidden { display: none !important; } .empty { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em; color: var(--fg-on-dark-3); margin: clamp(28px, 5vh, 52px) 0 0; font-feature-settings: "onum" 1; } :global(body:not(.dark)) .empty { color: var(--fg-3); } ``` (The `!important` on `.is-hidden` defends against any future row-level `display` rule overriding it.) - [ ] **Step 3: Verify the build and visual placement** Run: `npm run build 2>&1 | tail -10` Expected: Build succeeds. Run: `grep -c 'class="bsearch"' dist/blog/index.html` Expected: `1`. Run: `grep -c 'data-empty' dist/blog/index.html` Expected: `2` (the `

` and the inner ``). Run: `npm run dev` (background), open http://localhost:4321/blog, confirm the search input renders between the masthead and the featured article and looks at home with the rest of the page. Typing has no effect yet — that's expected. Then stop the dev server. - [ ] **Step 4: Commit** ```bash git add src/components/molecules/BlogSearch.astro src/pages/blog/index.astro git commit -m "feat(blog): render search input, empty-state, hidden utility" ``` --- ## Task 5: Add the filter script to `BlogSearch` **Files:** - Modify: `src/components/molecules/BlogSearch.astro` - [ ] **Step 1: Append the ` ``` A few notes for the engineer: - The script runs once at module-evaluation time after the DOM is parsed (Astro hoists `