A modern, accessible movie list application built with React 19, TypeScript, and Redux Toolkit that consumes the OMDB API (Open Movie Database).
- Real-time Movie Search - Search movies with debounced input (500ms delay)
- Custom Infinite Scroll - No external plugins, uses IntersectionObserver API
- Movie Details Modal - Click any movie card to view complete details
- Poster Preview Modal - Click movie poster to view full-size image
- Fully Responsive - Mobile-first design with Tailwind CSS v4
- WCAG AA Compliant - Meets accessibility standards (4.5:1 contrast ratio)
- Optimized Performance - React.memo, useCallback, custom hooks
- Modern UI/UX - Dark theme with smooth transitions
- React 19.2.0 - Latest React with TypeScript
- TypeScript 5.9.3 - Strict mode enabled (zero
anytypes) - Redux Toolkit - State management with async thunks
- Vite 7.2.7 - Lightning-fast build tool
- Tailwind CSS v4 - Utility-first styling
- Axios - HTTP client with singleton pattern
- Vitest - Unit testing framework
- Happy-DOM - Fast DOM implementation for tests
- Node.js - v20 or higher recommended
- npm or yarn or pnpm
- OMDB API Key - Get free key from omdbapi.com
# Clone repository
git clone <repository-url>
cd movie-list
# Install dependencies
npm install
# Create .env file
echo "VITE_OMDB_API_KEY=faf7e5bb" > .env
echo "VITE_OMDB_API_URL=http://www.omdbapi.com" >> .envnpm run devOpen http://localhost:5173 in your browser.
# Build for production
npm run build
# Preview production build
npm run preview# Run tests
npm test
# Run tests with UI
npm run test:ui
# Run tests with coverage
npm run test:coveragesrc/
├── components/
│ ├── commons/ # Feature-specific components
│ │ ├── error-boundary/
│ │ ├── error-message/
│ │ ├── loading-spinner/
│ │ ├── movie-card/
│ │ ├── movie-grid/
│ │ ├── movie-detail-modal/ # Feature modal
│ │ └── poster-modal/ # Feature modal
│ └── ui/ # Base/reusable UI components
│ ├── button/
│ ├── input/
│ ├── modal/ # Generic modal (supports variants)
│ └── search-box/
├── constants/
│ ├── apiConfig.ts # API endpoints & config
│ └── appConfig.ts # App-wide constants
├── hooks/
│ ├── use-debounce/ # Debounce hook (500ms)
│ ├── use-infinite-scroll/ # Custom infinite scroll
│ └── use-modal/ # Modal state management
├── libs/
│ └── axiosInstance.ts # Axios singleton instance
├── services/
│ └── movie-api/ # OMDB API service layer
│ ├── movieApi.ts
│ └── movieApi.types.ts
├── store/ # Redux store
│ ├── hooks.ts # Typed Redux hooks
│ ├── index.ts # Store configuration
│ └── slices/
│ └── movieSlice.ts
├── types/
│ ├── api.types.ts
│ └── movie.types.ts
├── App.tsx # Main app component
└── main.tsx # Entry point
- Uses custom
useDebouncehook (500ms delay) - Minimum 2 characters required for search
- Clears previous results when query changes
- Custom implementation using IntersectionObserver API
- Only activates when search results > 5 items
- Threshold: 200px from bottom
- Shows loading spinner during fetch
- Fetches complete movie data by IMDB ID
- Displays: plot, cast, director, ratings, awards, runtime
- Loading state with skeleton
- Error state with retry button
- Keyboard accessible (ESC to close)
- Click poster thumbnail to open full-size modal
- Loading state during image fetch
- Error state for failed images
- Close with backdrop click or ESC key
{
movies: {
searchResults: Movie[],
currentMovie: MovieDetail | null,
searchQuery: string,
currentPage: number,
totalResults: number,
isLoading: boolean,
isLoadingMore: boolean,
isLoadingDetail: boolean,
error: string | null,
hasMore: boolean
}
}- useDebounce - Delays value updates to reduce API calls
- useInfiniteScroll - Detects scroll position with IntersectionObserver
- useModal - Manages modal state, body scroll lock, ESC key handling
- WCAG AA compliant color contrast ratios (min 4.5:1)
- Keyboard navigation support (Tab, Enter, ESC)
- Proper ARIA labels on all interactive elements
- Semantic HTML elements (button, nav, main)
| Variable | Description | Default |
|---|---|---|
VITE_OMDB_API_KEY |
OMDB API key | faf7e5bb |
VITE_OMDB_API_URL |
OMDB API base URL | http://www.omdbapi.com |
Tests are written using:
- Vitest - Test runner
- @testing-library/react - Component testing utilities
- @testing-library/user-event - User interaction simulation
- happy-dom - Fast DOM environment
# Run all tests
npm test
# Watch mode
npm run test:watch
# Coverage report
npm run test:coverage# Production build
npm run build
# Output: dist/ folder ready for deploymentThe build is optimized with:
- Code splitting
- Tree shaking
- Minification
- Asset optimization
OMDB API
- Base URL:
http://www.omdbapi.com - Documentation: omdbapi.com
- Rate Limit: 1000 requests/day (free tier)
// Search movies
GET /?apikey={key}&s={query}&page={page}
// Get movie details
GET /?apikey={key}&i={imdbID}MIT License - feel free to use this project for learning purposes.
- Movie data from OMDB API
- Built with using React & TypeScript
Made with React 19 • TypeScript • Redux Toolkit • Tailwind CSS v4