News Lister
Vue 3 news aggregator with keyword search, pagination, and responsive design
Interview coding exercise — built for demonstration
A news article explorer built as a Vue.js coding exercise. It consumes a REST API to fetch news stories, renders article thumbnails with headlines, and provides links to full stories — all with a clean, responsive interface.
The Brief
The exercise required building a Vue.js application that consumes a REST API returning JSON objects — each containing thumbnail images, headlines, and source URLs for news articles about a given topic. The application needed to render article cards with images, provide clickable links to the full stories, support keyword search with autocomplete suggestions, and handle empty states gracefully when no articles match the current search term.
What made this interesting was the combination of requirements: the search needed to feel responsive without hammering the API on every keystroke, the pagination needed to work with the search state (not independently), and the empty state needed to distinguish between "no results for this query" and "API returned an error."
Search and Pagination
The search feature combines a text input with an autocomplete dropdown. As the user types, a debounced API call fetches matching article titles and displays them as suggestions below the input. Selecting a suggestion or pressing Enter triggers the full search, which fetches a paginated list of results — 10 articles per page — and renders them as a responsive card grid.
The pagination controls sit below the grid and update the query parameter without triggering a full page reload. The current page is tracked in the component state alongside the search query, so changing pages preserves the search term. This sounds obvious in retrospect, but the first implementation had page resetting to 1 on every search — a subtle UX bug that took a while to notice.
Architecture and Extensibility
The application separates data fetching from rendering through a composable-based architecture. A useNewsFeed composable handles API calls, pagination state, and search debouncing. The view components focus entirely on rendering — displaying article cards, managing the autocomplete dropdown, and showing the pagination bar.
This separation means the application can switch between news API providers by changing the composable's fetch logic, without touching any component. The composable returns a consistent interface (articles, loading, error, search, paginate), and the components don't care how those values are populated.
Architecture insight
The application is designed with a clean separation between data fetching, state management, and rendering. Swapping out the news feed source or modifying the UI components doesn't require changes to the core rendering logic — making it extensible by design.
Handling Edge Cases
The empty state handling went through several iterations. The first version simply showed "No articles found" when the results array was empty. But this message was misleading when the API returned an error — the user saw "No articles found" when the real problem was a network failure. The fix was to track error state separately from the results array, so the UI can distinguish between "no results" (valid search, zero matches) and "something broke" (network error, API limit, invalid key).
What I Learned
Designing for extensibility taught me that anticipating future requirements doesn't mean over-engineering. A simple interface contract between the data layer and the rendering layer — the composable returns articles, loading, and error — is enough to support future changes without locking in architectural decisions too early.
TypeScript with Vue 3's Composition API provides an excellent developer experience. Autocompletion in the template, refactoring support across composables, and compile-time error catching all contributed to a faster development cycle than plain JavaScript would have allowed. The type system caught several issues where I was accessing properties on potentially null objects — exactly the kind of bug that's hard to find at runtime.
Responsive design for card-based layouts requires thinking about content reflow, not just column count. On desktop, each card shows the full headline and a generous thumbnail. On mobile, the same card shows a truncated headline and a smaller image. The card component needs to know about its own responsive behavior, which means media queries in the component scope rather than a global layout breakpoint.
Nuxt?
This was built as a plain Vue 3 SPA with Vite. The exercise specifically required a single-page application setup rather than a framework with built-in routing. This kept the scope focused on component composition and API integration patterns.
Scripts
pnpm dev— Development serverpnpm build— Production buildpnpm test— Run tests with coveragepnpm lint— Lint source codepnpm format— Format with Prettier
Built as a coding exercise. View source · Live demo