BuyWhere Design System — Fashion & Apparel Category Page
Version: 1.0
Status: Ready for Iris Review
Parent: BUY-2235 (Sprint 2026-04-14 Design Artifacts)
Template #: 1 of 5
Owner: Proto (UI/UX Designer)
Last Updated: 2026-04-16
Deadline: EOD 2026-04-18
Overview
This document specifies the Fashion & Apparel category page template (template #1). Template #2 (Electronics) will follow.
Figma Frame Link: [To be inserted by Proto after Iris review]
Related Issues:
- Parent sprint: BUY-2149
- Design system tokens: BUY-2150
- Product cards (Iris): BUY-2130
Design Tokens Used
All measurements reference BuyWhere design system tokens from /static/css/tokens.css and fashion variant tokens from /static/css/product-fashion.css.
Fashion Variant Tokens:
--variant-accent: #e91e63; /* Pink — primary accent for Fashion/Beauty */
--variant-highlight: #f48fb1; /* Light pink — secondary accent */
--variant-bg-card: var(--color-bg-secondary);
Base Tokens Used:
- Spacing:
--space-1 through --space-16 (4px base)
- Typography:
--text-xs through --text-5xl
- Border radius:
--radius-sm (2px) through --radius-3xl (24px)
- Shadows:
--shadow-sm through --shadow-xl
- Transitions:
--duration-fast (100ms), --duration-normal (200ms), --duration-slow (300ms)
Frame 1: Desktop Layout (1440px viewport)
1.1 Layout Grid
┌─────────────────────────────────────────────────────────────────────────────┐
│ BREADCRUMB (Home > Women > Dresses > Maxi Dresses) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ CATEGORY HERO │ Subcategory pills (horizontal scroll) │
│ ───────────────────────────── │ [All] [Dresses] [Tops] [Bottoms]... │
│ WOMEN'S FASHION │ │
│ 12,847 products │ │
│ │
├────────────────┬──────────────────────────────────────────────────────────┤
│ │ TOOLBAR │
│ FILTER RAIL │ ───────────────────────────────────────────────────────── │
│ (Left, 280px)│ [Grid toggle] [Sort: Popular ▾] [12 / page] 1-12 of 12847│
│ ├──────────────────────────────────────────────────────────┤
│ □ Brand │ │
│ □ Price │ PRODUCT GRID (3-4 columns responsive) │
│ □ Size │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ □ Color │ │ │ │ │ │ │ │ │ │
│ □ Avail. │ │ Card │ │ Card │ │ Card │ │ Card │ │
│ □ Region │ │ │ │ │ │ │ │ │ │
│ │ └──────┘ └──────┘ └──────┘ └──────┘ │
│ [Clear All] │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ │ │ │ │ │ │ │ │ │
│ │ │ Card │ │ Card │ │ Card │ │ Card │ │
│ │ │ │ │ │ │ │ │ │ │
│ │ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │ │
│ │ PAGINATION │
│ │ < Prev 1 2 3 ... 1071 Next > │
└────────────────┴──────────────────────────────────────────────────────────┘
1.2 Section Specifications
Breadcrumb
| Property | Value |
|---|
| Container | Full width, padding --space-4 horizontal |
| Font | --text-sm, --font-medium |
| Color | --color-text-secondary (default), --color-link (links) |
| Separator | / with --color-text-tertiary |
| Last item | --color-text-primary, no link |
| Hover (links) | --color-link-hover, underline |
| Spacing between items | --space-2 |
Category Hero
| Property | Value |
|---|
| Container | Full width, padding --space-8 vertical, --space-4 horizontal |
| Background | --color-bg-secondary (#f9fafb) with subtle gradient overlay |
| Title font | --text-4xl (36px), --font-bold, --tracking-tight |
| Title color | --color-text-primary |
| Product count font | --text-lg, --font-normal |
| Product count color | --color-text-secondary |
| Bottom margin | --space-6 |
Subcategory Pills (below hero)
| Property | Value |
|---|
| Container | Horizontal scroll, --space-4 vertical padding |
| Gap between pills | --space-2 |
| Pill padding | --space-2 --space-4 |
| Pill background (default) | --color-bg-primary, border 1px --color-border-default |
| Pill background (active) | --variant-accent (#e91e63) |
| Pill text (default) | --text-sm, --font-medium, --color-text-primary |
| Pill text (active) | White |
| Pill border-radius | --radius-full (9999px) |
| Pill hover (default) | border --variant-accent, text --variant-accent |
| Transition | --duration-fast --ease-out |
Filter Rail (Left Sidebar)
| Property | Value |
|---|
| Width | 280px fixed |
| Padding | --space-4 |
| Background | --color-bg-primary |
| Border-right | 1px --color-border-default |
| Section spacing | --space-6 between filter groups |
Filter Section Header
| Property | Value |
|---|
| Font | --text-sm, --font-semibold |
| Color | --color-text-primary |
| Margin-bottom | --space-3 |
| Toggle icon | Chevron down, rotates 180° when collapsed |
| Toggle size | 16px |
Filter Group: Brand (Checkbox List)
| Property | Value |
|---|
| Checkbox size | 18px × 18px |
| Checkbox border | 2px --color-border-default |
| Checkbox checked bg | --variant-accent (#e91e63) |
| Checkbox checked icon | White checkmark, 12px |
| Label font | --text-sm, --font-normal |
| Label color | --color-text-primary |
| Count color | --color-text-tertiary |
| Count font | --text-xs |
| Item spacing | --space-2 between items |
| Max visible before scroll | 6 items (then scroll) |
| Scroll max-height | 200px |
Filter Group: Price Range (Range Slider)
| Property | Value |
|---|
| Track height | 4px |
| Track background | --color-border-default |
| Fill color | --variant-accent |
| Thumb size | 18px circle |
| Thumb color | --variant-accent |
| Thumb border | 2px white |
| Thumb shadow | --shadow-sm |
| Value display | --text-xs, --font-medium, above thumb |
| Input fields | Min/Max price, --input-height-md, --space-2 gap |
Filter Group: Size (Pill Toggle)
| Property | Value |
|---|
| Pill size | 40px × 40px |
| Pill background (default) | --color-bg-primary |
| Pill border (default) | 1px --color-border-default |
| Pill background (selected) | --variant-accent |
| Pill border (selected) | --variant-accent |
| Pill text (selected) | White, --font-medium |
| Pill border-radius | --radius-lg (8px) |
| Gap | --space-2 |
| Wrap | yes |
Filter Group: Color (Swatch Grid)
| Property | Value |
|---|
| Swatch size | 32px × 32px |
| Swatch border-radius | --radius-full |
| Swatch border (default) | 2px transparent |
| Swatch border (selected) | 2px --variant-accent |
| Swatch ring on hover | 2px --color-border-strong, offset 2px |
| Gap | --space-2 |
| Color label below selected | --text-xs, --color-text-secondary |
Filter Group: Availability (Toggle)
| Property | Value |
|---|
| Toggle style | Switch (not checkbox) |
| Toggle width | 40px |
| Toggle height | 22px |
| Track off | --color-border-default |
| Track on | --variant-accent |
| Thumb | 18px circle, white |
Filter Group: Region (Dropdown)
| Property | Value |
|---|
| Style | Same as filter dropdown |
| Options | Singapore, Malaysia, Indonesia, Thailand, Vietnam, Global |
Filter Actions
| Property | Value |
|---|
| Clear All button | Ghost button, --text-sm, --font-medium |
| Clear All color | --color-text-secondary |
| Clear All hover | --color-text-primary |
| Clear All visible when | Any filter active |
Active Filters Bar (above grid)
| Property | Value |
|---|
| Container | Full width, padding --space-3 --space-4 |
| Background | --color-primary-50 (#eef2ff) |
| Border-radius | --radius-lg |
| Gap between chips | --space-2 |
| Chip padding | --space-1 --space-3 |
| Chip background | --color-bg-primary |
| Chip border | 1px --color-border-default |
| Chip font | --text-xs, --font-medium |
| Chip remove icon | 14px, --color-text-tertiary |
| Chip remove hover | --color-text-primary |
Toolbar
| Property | Value |
|---|
| Container | Full width, padding --space-3 --space-4 |
| Background | --color-bg-primary |
| Border-bottom | 1px --color-border-subtle |
| Item spacing | --space-3 |
| Margin-bottom | --space-4 |
Grid/List Toggle
| Property | Value |
|---|
| Button group | 2 buttons, connected |
| Button size | 36px × 36px |
| Button background (default) | transparent |
| Button background (active) | --color-bg-secondary |
| Button icon | 20px, --color-text-secondary |
| Button icon (active) | --color-text-primary |
| Border-radius | --radius-md |
| Border | 1px --color-border-default |
Sort Dropdown
| Property | Value |
|---|
| Trigger width | 160px |
| Trigger padding | --space-2 --space-3 |
| Trigger font | --text-sm, --font-medium |
| Trigger background | --color-bg-primary |
| Trigger border | 1px --color-border-default |
| Trigger border-radius | --radius-lg |
| Chevron icon | Right, 16px |
| Dropdown max-height | 240px |
| Dropdown item padding | --space-2 --space-3 |
| Dropdown item hover | --color-bg-secondary |
| Dropdown item font | --text-sm |
Sort Options:
- Popular (default)
- Price: Low to High
- Price: High to Low
- Newest Arrivals
- Best Rated
- Biggest Discount
Results Per Page
| Property | Value |
|---|
| Style | Segmented control |
| Options | 12, 24, 48 |
| Button height | 32px |
| Active background | --variant-accent |
| Active text | White |
Product Count
| Property | Value |
|---|
| Font | --text-sm |
| Color | --color-text-secondary |
| Range text | "1-12 of 12,847" |
Product Grid
| Property | Value |
|---|
| Container padding | --space-4 |
| Columns (1440px+) | 4 |
| Columns (1024px-1439px) | 3 |
| Columns (768px-1023px) | 2 |
| Gap | --space-4 |
| Card min-width | 200px |
| Card max-width | none (fluid) |
Product Card (Fashion Variant — reuse from BUY-2130)
| Property | Value |
|---|
| Background | --color-bg-primary |
| Border | 1px --color-border-default |
| Border-radius | --radius-xl (12px) |
| Image aspect ratio | 3/4 (portrait, fashion) |
| Image object-fit | cover |
| Hover border | --variant-accent |
| Hover shadow | --shadow-lg |
| Hover transform | translateY(-4px) |
| Badge position | Top-left, --space-2 |
| Badge background | --variant-accent |
| Badge text | White, --text-xs, --font-bold |
| Quick-add button | Slides up on card hover |
| Quick-add background | --color-bg-primary |
Pagination
| Property | Value |
|---|
| Container | Centered, --space-6 vertical |
| Gap between items | --space-1 |
| Page button size | 36px × 36px |
| Page button background (default) | transparent |
| Page button background (active) | --variant-accent |
| Page button text (active) | White |
| Page button border-radius | --radius-md |
| Ellipsis | --text-sm, --color-text-tertiary |
| Prev/Next | Ghost style, --text-sm |
| Disabled state | opacity 0.5, pointer-events none |
Frame 2: Mobile Layout (375px viewport, ≤768px)
2.1 Layout Structure
┌─────────────────────────┐
│ ≡ BuyWhere [🔍] │ ← Sticky header
├─────────────────────────┤
│ Home / Women / Dresses │ ← Breadcrumb (truncated)
├─────────────────────────┤
│ │
│ WOMEN'S FASHION │
│ 12,847 products │
│ │
├─────────────────────────┤
│ [Filters (3)] [Sort ▾] │ ← Sticky toolbar
│ [Grid▾] [List▾] │
├─────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │ │ │ │ │
│ │ Card │ │ Card │ │ ← 2-column grid
│ │ │ │ │ │
│ └─────────┘ └─────────┘ │
│ ┌─────────┐ ┌─────────┐ │
│ │ │ │ │ │
│ │ Card │ │ Card │ │
│ │ │ │ │ │
│ └─────────┘ └─────────┘ │
│ │
│ < Prev 1 2 3 ... Next >│
│ │
└─────────────────────────┘
FILTER DRAWER (slides from left):
┌─────────────────────────┐
│ ✕ Filters [Clear] │
├─────────────────────────┤
│ □ Brand [▾] │
│ □ Price [▾] │
│ □ Size [▾] │
│ □ Color [▾] │
│ □ Availability [▾] │
│ □ Region [▾] │
├─────────────────────────┤
│ │
│ [ Apply (847) ] │ ← Sticky bottom
│ │
└─────────────────────────┘
2.2 Mobile Specifications
Sticky Header
| Property | Value |
|---|
| Height | 56px |
| Background | --color-bg-primary |
| Border-bottom | 1px --color-border-default |
| Logo | Left, 80px wide |
| Search icon | Right, 44px tap target |
| Menu icon | Left, 44px tap target |
Mobile Breadcrumb
| Property | Value |
|---|
| Font | --text-xs |
| Color | --color-text-tertiary |
| Padding | --space-3 --space-4 |
| Truncation | Ellipsis after 2 items |
Mobile Category Hero
| Property | Value |
|---|
| Padding | --space-4 |
| Title font | --text-2xl (24px), --font-bold |
| Count font | --text-sm |
Mobile Filter/Sort Toolbar
| Property | Value |
|---|
| Position | Sticky, below header |
| Height | 48px |
| Background | --color-bg-primary |
| Border-bottom | 1px --color-border-subtle |
| Filter button | Shows active filter count badge |
| Sort button | Full width dropdown |
| View toggle | Icon only, right side |
Mobile Filter Drawer
| Property | Value |
|---|
| Width | 85% of screen (max 320px) |
| Position | Slides from left |
| Background | --color-bg-primary |
| Overlay | --overlay-background (50% black) |
| Header height | 56px |
| Close button | Left, 44px tap target |
| Apply button | Fixed bottom, full width minus padding |
| Apply button height | 48px |
| Apply button background | --variant-accent |
| Apply button text | White, --font-semibold |
Mobile Subcategory Pills
| Property | Value |
|---|
| Container | Horizontal scroll |
| Padding | --space-3 horizontal |
| Pill height | 36px |
Mobile Product Grid
| Property | Value |
|---|
| Columns | 2 |
| Gap | --space-3 |
| Card min-width | none (fluid 50% - gap) |
Mobile Product Card
| Property | Value |
|---|
| Border-radius | --radius-lg |
| Image aspect ratio | 3/4 |
| Quick-add | Hidden on mobile (tap opens PDP) |
| Merchant badge | Smaller, --text-xs |
Mobile Pagination
| Property | Value |
|---|
| Page buttons | 32px × 32px |
| Truncation | Show 1, ... , 3 pages from ends |
Frame 3: Empty / No Results State
┌─────────────────────────────────────────────────────────────────────────────┐
│ BREADCRUMB │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ CATEGORY HERO │
│ ───────────────────────────── │
│ WOMEN'S FASHION │
│ 0 products │
│ │
├────────────────┬──────────────────────────────────────────────────────────┤
│ │ │
│ FILTER RAIL │ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │ │
│ │ │ 🔍 │ │
│ │ │ │ │
│ │ │ No results for "Red Dresses" │ │
│ │ │ │ │
│ │ │ Try adjusting your filters or search terms │ │
│ │ │ │ │
│ │ │ Suggestions: │ │
│ │ │ • Remove some filters │ │
│ │ │ • Search for a different keyword │ │
│ │ │ • Browse our popular categories │ │
│ │ │ │ │
│ │ │ [Clear All Filters] [Browse All Dresses] │ │
│ │ │ │ │
│ │ └─────────────────────────────────────────────────────┘ │
│ │ │
└────────────────┴──────────────────────────────────────────────────────────┘
Empty State Specifications
| Property | Value |
|---|
| Container | Centered in grid area, max-width 400px |
| Icon size | 64px |
| Icon color | --color-text-tertiary |
| Title font | --text-xl, --font-semibold |
| Title color | --color-text-primary |
| Description font | --text-base, --font-normal |
| Description color | --color-text-secondary |
| Suggestion list | --text-sm, --color-text-secondary |
| Button spacing | --space-3 between buttons |
| Clear Filters button | Ghost variant |
| Browse All button | Primary variant, --variant-accent |
Frame 4: Loading / Skeleton States
4.1 Initial Page Load Skeleton
┌─────────────────────────────────────────────────────────────────────────────┐
│ ████████████████ │ ← Breadcrumb skeleton
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ████████████████████████████████████ │ ← Hero title
│ ████████████ │ ← Product count
│ │
├────────────────┬──────────────────────────────────────────────────────────┤
│ │ ████████ ██████████ ████ ████████████ │ ← Toolbar
│ FILTER RAIL ├──────────────────────────────────────────────────────────┤
│ (disabled) │ │
│ │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ ████████ │ │ │ │ │ │ │ │ │ │
│ ████████ │ │ ░░░░ │ │ ░░░░ │ │ ░░░░ │ │ ░░░░ │ ← Image skeleton │
│ ████████ │ │ ░░░░ │ │ ░░░░ │ │ ░░░░ │ │ ░░░░ │ │
│ ████████ │ └──────┘ └──────┘ └──────┘ └──────┘ │
│ ████████ │ ████████████ ████████████ ← Brand + Title │
│ ████████ │ ████████ ████████ ← Price │
│ │ │
│ │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ │ │ │ │ │ │ │ │ │
│ │ │ ░░░░ │ │ ░░░░ │ │ ░░░░ │ │ ░░░░ │ │
│ │ │ ░░░░ │ │ ░░░░ │ │ ░░░░ │ │ ░░░░ │ │
│ │ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │ │
└────────────────┴──────────────────────────────────────────────────────────┘
4.2 Skeleton Specifications
Skeleton Animation
| Property | Value |
|---|
| Animation | Shimmer left-to-right |
| Base color | --color-bg-tertiary (#f3f4f6) |
| Highlight color | --color-bg-secondary (#f9fafb) |
| Duration | 1.5s per cycle |
| Easing | ease-in-out |
| Loop | Infinite |
Skeleton Shapes
| Element | Shape | Size |
|---|
| Breadcrumb | Rounded rectangle | 80px × 12px |
| Hero title | Rounded rectangle | 200px × 36px |
| Hero count | Rounded rectangle | 100px × 16px |
| Filter section | Rounded rectangle | 100% width × 24px |
| Filter item | Rounded rectangle | 80% width × 16px |
| Product image | Rounded rectangle | 100% × aspect 3:4 |
| Product brand | Rounded rectangle | 60px × 12px |
| Product title | Rounded rectangle | 100% × 16px (2 lines) |
| Product price | Rounded rectangle | 70px × 20px |
4.3 Filter Loading State
- Filter options show skeleton while loading
- Apply button shows spinner when submitting
- 200ms minimum display to prevent flash
4.4 Grid Loading (Pagination)
| Property | Value |
|---|
| Style | Replace existing cards with skeletons |
| Transition | Fade out old → fade in new |
| Duration | 200ms |
Interaction Notes
Facet Filter Behavior
Multi-Select Filters (Brand, Size, Color)
- User taps checkbox/pill → immediate UI update (optimistic)
- Active filter chip appears in filter bar
- URL updates with filter params (
?brand=nike,adidas&size=s,m)
- Product grid reloads with loading skeleton
- Results count updates in toolbar
- If API fails → revert filter, show toast error
Single-Select Filters (Availability, Region)
- User toggles switch / selects option
- Immediate UI feedback
- URL updates
- Grid reloads
Price Range Filter
- User drags sliders OR enters values in min/max inputs
- Debounce 300ms before API call
- Price chips show "S$XX - S$XXX" format
- Clear price filter shows "All Prices"
Filter Drawer (Mobile)
- Tap "Filters" → drawer slides in from left (300ms, ease-out)
- Tap overlay OR tap X → drawer slides out
- Tap "Apply" → drawer closes, filters apply
- Badge on Filters button shows active count
Sort Interaction
- Tap sort dropdown → options expand below
- Tap option → dropdown closes, sort applies
- Grid re-sorts with loading state
- Dropdown trigger shows selected option
Grid/List Toggle
- Tap toggle → immediate view change
- Preference saved to localStorage
- List view: horizontal card layout, 1 column
- List card: image 120px × 120px, horizontal details
Active Filters
- Tap chip X → removes that filter
- Tap "Clear All" → removes all active filters
- Each removal triggers grid reload
Error States
| Scenario | Behavior |
|---|
| Filter API fails | Toast "Couldn't update filters. Try again." + revert filter |
| Product load fails | Retry button in grid area, "Couldn't load products" |
| Network offline | Banner at top "You're offline. Showing cached results." |
Component Inventory
Components Used (from BUY-2150)
- Button — Primary, Ghost, Danger variants
- Checkbox — Custom styled with variant-accent
- Toggle Switch — For availability filter
- Dropdown/Select — For sort, region
- Pagination — Numbered with prev/next
- Skeleton — Shimmer animation
- Toast — Error notifications
- Badge — Active filter chips
- Icon — Chevron, grid, list, close, search, filter
Fashion-Specific Components
- Color Swatch — With selection ring
- Size Pill — Toggle with selected state
- Subcategory Pill — Horizontal scroll tabs
- Active Filter Chip — With remove action
- Quick-Add Button — Slides up on hover (desktop only)
Accessibility Requirements
| Requirement | Implementation |
|---|
| Focus visible | 2px --focus-ring-color outline on all interactive elements |
| Keyboard navigation | Tab through filters, Enter/Space to toggle, Escape to close drawer |
| Screen reader | aria-label on icon buttons, aria-pressed on toggles, aria-current="page" on pagination |
| Filter announce | aria-live="polite" region announces result count changes |
| Mobile drawer | Focus trap inside drawer when open, restore focus on close |
| Color contrast | All text meets WCAG AA (4.5:1 normal, 3:1 large) |
| Reduced motion | Respect prefers-reduced-motion — disable shimmer, simplify transitions |
Responsive Breakpoints
| Breakpoint | Layout |
|---|
| ≥1024px | Desktop: sidebar + 3-4 column grid |
| 768px-1023px | Tablet: sidebar collapsed to icons + 2-3 column grid |
| ≤767px | Mobile: filter drawer + 2 column grid |
Handoff Notes for Engineering
CSS Structure
/static/css/
category.css # Base category styles (existing)
category-fashion.css # NEW: Fashion category variant (extends category.css)
Template File
/templates/
category-fashion.html # NEW: Fashion category Jinja2 template
Key CSS Classes
| Class | Purpose |
|---|
.category-page | Page container |
.category-hero | Hero section |
.category-filters | Filter rail/sidebar |
.filter-group | Individual filter section |
.filter-chip | Active filter tag |
.category-toolbar | Sort, toggle, count bar |
.product-grid | Product card container |
.product-grid--list | List view modifier |
.skeleton-card | Loading skeleton card |
.empty-state | No results view |
API Integration Points
| Action | Endpoint |
|---|
| Load products | GET /api/catalog/category/{id}?filters=...&sort=...&page=... |
| Load filters | GET /api/catalog/category/{id}/filters |
| Update filter | Triggers product reload via query params |
Sign-Off
| Role | Name | Status | Date |
|---|
| Designer | Proto | Ready for Review | 2026-04-16 |
| Design Review | Iris | Pending | — |
| Engineering Build | Hue/Sol | Pending | — |
Figma frames will be linked after Iris review approval.