# Calendar renders without layout overflow across 320 to 1440px viewports

- **Pattern:** `ab-000522` (`booking-calendar-availability.calendar-display.responsive-rendering`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000522
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000522)

## Why it matters

A booking calendar that requires horizontal scrolling at 320px fails WCAG 2.2 SC 1.4.10 (Reflow) and locks out users on low-end Android devices, which represent a disproportionate share of mobile traffic in emerging markets. Fixed-width calendar grids are one of the most common causes of horizontal overflow: a 7-column week grid with fixed column widths adds up to 700px or more on desktop, which is unreadable on mobile. Missing viewport meta tags compound this by preventing the browser from scaling correctly. The result is that mobile users see a broken, unreadable booking interface and leave.

## Severity rationale

Low because horizontal overflow is a usability defect rather than a data-integrity risk, but it directly excludes mobile users and violates WCAG 2.2 SC 1.4.10 (Reflow).

## Remediation

Replace fixed-width calendar grid containers with responsive Tailwind utility classes and ensure `src/app/layout.tsx` includes the viewport meta tag.

```tsx
// src/components/Calendar.tsx
export function Calendar({ slots }) {
  return (
    <div className="w-full overflow-hidden">
      {/* 1-col on mobile, 4-col on tablet, 7-col on desktop */}
      <div className="grid grid-cols-1 sm:grid-cols-4 lg:grid-cols-7 gap-1">
        {slots.map(slot => <CalendarSlot key={slot.id} {...slot} />)}
      </div>
    </div>
  )
}
```

In `src/app/layout.tsx`, confirm the viewport meta tag is present:

```tsx
export const metadata = {
  // ...
  viewport: 'width=device-width, initial-scale=1',
}
```

Test at 320px, 375px, 768px, 1024px, and 1440px using browser DevTools device emulation — no element should extend past the viewport edge.

## Detection

- **ID:** `responsive-rendering`
- **Severity:** `low`
- **What to look for:** Enumerate all viewport breakpoints to test: 320px, 375px, 768px, 1024px, 1440px. For each, inspect the calendar component's CSS for responsive classes (e.g., `grid-cols-1 sm:grid-cols-4 lg:grid-cols-7`), `overflow-x`, `max-width: 100%`. Check for a viewport meta tag in the root layout: `<meta name="viewport" content="width=device-width, initial-scale=1">`. Look for fixed-width containers that could cause horizontal scroll. Examine files matching `src/app/layout.tsx`, `src/components/*Calendar*`, `src/app/*booking*/page.tsx`.
  1. 320px (mobile, iPhone SE)
  2. 375px (mobile, iPhone 14)
  3. 768px (tablet)
  4. 1024px (desktop)
  5. 1440px (large desktop)
- **Pass criteria:** Count all 5 viewport breakpoints. Calendar must display without horizontal scroll at all 5 widths. The root layout must include a viewport meta tag with `width=device-width`. No more than 0 breakpoints may show horizontal overflow or clipped interactive elements. Report: "X of 5 viewport breakpoints render without horizontal overflow."
- **Fail criteria:** Calendar requires horizontal scrolling at any tested width, or elements are clipped off-screen, or viewport meta tag is missing.
- **Skip (N/A) when:** Calendar is explicitly desktop-only (e.g., admin-only dashboard with no mobile requirement).
- **Detail on fail:** Example: `"At 320px, the calendar grid overflows right by 100px. Users must scroll horizontally to see time slots."`
- **Cross-reference:** Check `keyboard-navigation` — responsive layout must preserve logical tab order at narrow viewports.
- **Cross-reference:** Check `performance-load-time` — responsive images and lazy loading help mobile performance.
- **Cross-reference:** Check `visual-distinction` — slot indicators must remain visible and readable at 320px width.
- **Remediation:** Use responsive CSS or a responsive calendar library:

  ```tsx
  export function Calendar() {
    return (
      <div className="w-full overflow-hidden">
        {/* Use grid that adjusts columns by breakpoint */}
        <div className="grid grid-cols-1 sm:grid-cols-4 lg:grid-cols-7 gap-1">
          {slots.map((slot) => (
            <CalendarSlot key={slot.id} {...slot} />
          ))}
        </div>
      </div>
    )
  }
  ```

  Or use a library like FullCalendar with responsive CSS:

  ```css
  .fc {
    max-width: 100%;
    overflow-x: auto;
  }
  ```

## External references

- wcag 1.4.10

Taxons: user-experience

HTML version: https://auditbuffet.com/patterns/ab-000522
