A lightweight, accessible, and responsive image carousel built from scratch with React + TypeScript and Tailwind CSS.
Supports keyboard navigation, swipe/drag and optional thumbnails—perfect as a portfolio showcase.
autoplay with sensible pause rules, lazy loading, and optional thumbnails—perfect as a portfolio showcase.
You can find the Image Carousel here.
- A11y-first: roles, live region updates, keyboard (←/→), visible focus
- Touch & mouse swipe: horizontal threshold + vertical scroll guard
- Autoplay: interval timer, pause on hover, pause when tab hidden
- Virtualized slides: render only current ±1 for smooth performance
- Lazy loading & neighbor prefetch
- Clean UI: full-bleed or padded-card layouts, indicators, captions
- Configurable: loop/clamp, aspect ratio (16:9 by default)
- TypeScript: typed props and events for clarity
- React + TypeScript
- Vite (dev/build)
- Tailwind CSS (utility styling)
npm create vite@latest image-carousel -- --template react-ts
cd image-carousel
npm installnpm run dev- Root has
role="region"andaria-roledescription="carousel". - Buttons have
aria-label: “Previous slide”, “Next slide”. - Play/Pause (if present) uses
aria-pressed. - Indicators are buttons:
aria-label="Go to slide N". - Live region announces: “Slide X of Y: {alt}”.
- Keyboard:
- Left/Right arrows navigate when the stage is focused.
- Visible focus rings on interactive elements.
Navigation
- Prev/Next buttons (overlay, center-left/right)
- Clickable indicators (dots)
- Optional thumbnails (click-to-jump)
Autoplay
- Single timeout schedules
next()atinterval - Paused on: hover, dragging, or hidden tab (
visibilitychange) - Resumes when conditions clear
MVP
- Stage with fixed aspect (16:9), single image rendering
- Prev/Next buttons + indicators (dots)
- Keyboard arrows
- Base a11y labels
- Deploy MVP demo
Core polish
- Autoplay + hover pause + visibility pause
- Live region announcements
- Lazy load + neighbor prefetch
- (Optional) Virtualize slides (current ±1)
Future
- Thumbnails strip
- Storybook variants
- Tests (autoplay timing, keyboard, a11y)
- Lightbox modal (zoom/pan)
- Buttons, dots, keyboard all navigate correctly
- Loop on/off works (wrap vs clamp with disabled edges)
- Autoplay pauses on hover, drag, and hidden tab; resumes properly
- Screen reader announces “Slide X of Y: alt”
- Only current ±1 slides mounted (when virtualization on)
- No console warnings; layout stable on resize
- Tailwind v4 PostCSS error:
Install@tailwindcss/postcssand use it inpostcss.config.js. - npx on Windows can’t find Tailwind:
Install locally, then runnode node_modules/tailwindcss/lib/cli.js init -p. - Image too tall / too short:
Ensure the stage has a fixed aspect (e.g.,aspect-video), make image fill and useobject-cover(orobject-containfor letterboxing). - Arrows not clickable with overlay:
Don’t setpointer-events: noneon the controls wrapper; keep it clickable and layer it above the image.
Unsplash for demo images; you for building a clean, accessible carousel from scratch.