---
estimated_steps: 56
estimated_files: 7
skills_used: []
---

# T03: TagList component, tag overflow limit, and empty subtopic handling

Create a shared TagList component for tag overflow (R027), apply it across all 5 tag-rendering sites, and add empty subtopic handling in TopicsBrowse (R028).

## Steps

1. Create `frontend/src/components/TagList.tsx`:
   ```tsx
   interface TagListProps {
     tags: string[];
     max?: number;
   }
   export default function TagList({ tags, max = 4 }: TagListProps) {
     const visible = tags.slice(0, max);
     const overflow = tags.length - max;
     return (
       <>
         {visible.map(tag => <span key={tag} className="pill">{tag}</span>)}
         {overflow > 0 && <span className="pill pill--overflow">+{overflow} more</span>}
       </>
     );
   }
   ```

2. Add `.pill--overflow` CSS in `frontend/src/App.css`:
   ```css
   .pill--overflow {
     background: var(--color-surface-2);
     color: var(--color-text-secondary);
     font-style: italic;
   }
   ```

3. Replace tag rendering in all 5 sites with `<TagList tags={...} />`:
   - `frontend/src/pages/Home.tsx` line ~201 (featured technique tags) — replace `featured.topic_tags.map(...)` with `<TagList tags={featured.topic_tags} />`
   - `frontend/src/pages/Home.tsx` line ~247 (recent technique card tags) — replace `t.topic_tags.map(...)` with `<TagList tags={t.topic_tags} />`
   - `frontend/src/pages/SearchResults.tsx` line ~145 — replace `item.topic_tags.map(...)` with `<TagList tags={item.topic_tags} />`
   - `frontend/src/pages/SubTopicPage.tsx` line ~149 — replace `t.topic_tags.map(...)` with `<TagList tags={t.topic_tags} />`
   - `frontend/src/pages/CreatorDetail.tsx` line ~157 — replace `t.topic_tags.map(...)` with `<TagList tags={t.topic_tags} />`
   Each site: add `import TagList from "../components/TagList";` and replace the `.map(tag => <span className="pill">{tag}</span>)` with `<TagList tags={...} />`.

4. In `frontend/src/pages/TopicsBrowse.tsx`, update the subtopic rendering inside the `.topic-subtopics` div. For subtopics with `st.technique_count === 0`:
   - Render as a `<span>` (not `<Link>`) with class `topic-subtopic topic-subtopic--empty` instead of a clickable link
   - Add a small "Coming soon" badge: `<span className="pill pill--coming-soon">Coming soon</span>`
   - Keep the subtopic name visible so users know the topic exists
   Use a conditional: `st.technique_count === 0 ? <span className="topic-subtopic topic-subtopic--empty">...</span> : <Link ...>...</Link>`

5. Add CSS for empty subtopic in `frontend/src/App.css`:
   ```css
   .topic-subtopic--empty {
     opacity: 0.5;
     cursor: default;
   }
   .topic-subtopic--empty:hover {
     background: transparent;
   }
   .pill--coming-soon {
     font-size: 0.65rem;
     background: var(--color-surface-2);
     color: var(--color-text-secondary);
     font-style: italic;
   }
   ```

6. Verify: `cd frontend && npx tsc --noEmit && npm run build`

## Inputs

- `frontend/src/pages/Home.tsx`
- `frontend/src/pages/SearchResults.tsx`
- `frontend/src/pages/SubTopicPage.tsx`
- `frontend/src/pages/CreatorDetail.tsx`
- `frontend/src/pages/TopicsBrowse.tsx`
- `frontend/src/App.css`

## Expected Output

- `frontend/src/components/TagList.tsx`
- `frontend/src/pages/Home.tsx`
- `frontend/src/pages/SearchResults.tsx`
- `frontend/src/pages/SubTopicPage.tsx`
- `frontend/src/pages/CreatorDetail.tsx`
- `frontend/src/pages/TopicsBrowse.tsx`
- `frontend/src/App.css`

## Verification

cd frontend && npx tsc --noEmit && npm run build
