A responsive search interface built with Next.js 15, React 19, TypeScript, and Tailwind(v4) CSS. Features include infinite scrolling with virtualized lists, client-side bookmark functionality using Zustand, and comprehensive error handling.
This project is a search interface built using modern web technologies. It enables users to search for content, view results in an optimized virtual list, and bookmark items of interest.
This project includes integration with the Google Custom Search API through built-in Next.js API routes, making it possible to use this project with Google's search results while maintaining the same UI and functionality. The API routes act as a proxy, handling:
- Converting Google search results to match the expected API format
- Providing useful error messages for API quota limits
- Keeping all API keys secure on the server
Framework: Next.js 15 with App Router for routing and server components
Language: TypeScript for type safety
Styling: Tailwind(v4) for utility-first styling
Data Fetching: TanStack Query (formerly React Query) for data fetching, caching, and state management
State Management: Zustand for client-side state management
List Virtualization: React Virtuoso for efficient rendering of large lists
Linting/Formatting: Biome for linting and code formatting
Git Hooks: Husky for pre-commit hooks
- Search functionality with
Enterkey support Infinite scrollingwith virtualized list for performance- Bookmark/unbookmark functionality with Zustand for state management and React-query's
optimistic updates - Error handling with
dialogfeedback - Responsive design
Image fallbacksfor failed favicon/thumbnailLoading skeletonsduring content fetching
src/
├── app/ # Next.js App Router files
│ ├── (home)/ # Home page route
│ ├── results/ # Search results route
│ │ ├── components/ # Results page components
│ │ └── page.tsx # Results page component
│ ├── api/ # API routes
│ │ └── search/ # Search API endpoints
│ ├── error.tsx # Global error handling
│ ├── layout.tsx # Root layout
│ └── providers.tsx # React context providers
├── components/ # Shared UI components
│ ├── Card/ # Content card components
│ ├── ErrorModal/ # Error display modal
│ ├── SearchBox/ # Search input component
│ ├── Skeletons/ # Loading placeholders
│ └── Svg/ # SVG icons
├── lib/ # Utility libraries
│ ├── api/ # API functions
│ ├── errors/ # Error handling utilities
│ └── store/ # Zustand stores
├── services/ # Service layer
│ ├── bookmarkService.ts # Bookmark management
│ └── contentService.ts # Content fetching
├── styles/ # Global styles
└── types/ # TypeScript types
└── api.ts # API-related types
The application interacts with one main API endpoint:
(GET) - getContents: Fetches contents based on search query.
- Search is triggered on
Enterkey press - Results are fetched using TanStack Query's
useInfiniteQuery - Pagination is handled through the
fromparameter in the API
Implemented using React Virtuoso to efficiently render only the visible items in the search results list, significantly improving performance for large result sets.
- Powered by
Zustandfor client-side state management - Session-based bookmarks that reset on page refresh
Optimistic updatesfor immediate UI feedback- Error handling with
automatic state rollbackif operations fail - Modal feedback for error conditions
Error boundariesfor unexpected runtime errors- API error handling with user feedback via
modals Fallback imagesfor failed image loading
Node.js 18+ and Yarn
git clone https://github.com/regisBafutwabo/search.git
cd searchyarncp .env.example .env.localEdit .env.local with your API keys and configuration:
# Google API configuration (required for Google search)
NEXT_PUBLIC_GOOGLE_CUSTOM_SEARCH_KEY=your_google_api_key
NEXT_PUBLIC_GOOGLE_CUSTOM_SEARCH_API_URL=https://www.googleapis.com/customsearch/v1
NEXT_PUBLIC_GOOGLE_CUSTOM_SEARCH_ENGINE_ID=your_search_engine_id
- Go to Google Cloud Console
- Create a new project
- Enable the "Custom Search API"
- Create API credentials (API Key)
- Go to Google Programmable Search Engine
- Create a new search engine
- Get your Search Engine ID (cx parameter)
- Add both the API Key and Search Engine ID to your .env.local file
yarn dev