Hacker News is a staple for developers, but its minimalist design hasn't evolved much over the years. As a developer who spends hours reading tech news, I decided to build Hacker News 2026—a modern, high-performance client that prioritizes UX without sacrificing the original's speed.
In this post, I'll walk you through the technical architecture, the challenges of real-time data, and how I built a robust theme system.
The Architecture: Component-Driven and Hook-Heavy
I chose React 18 and Vite for the foundation. React's component-based architecture is perfect for managing the complex comment trees and story lists that Hacker News requires.
1. Data Fetching: The Service Layer
Instead of scattering fetch calls across components, I built a dedicated service layer (hnApi.ts) that interacts with the Hacker News Firebase API. This layer handles:
- Fetching story IDs for different categories (Top, New, Best, etc.).
- Batch fetching items (stories, comments, users) to minimize network overhead.
- Domain extraction for cleaner story cards.
// src/services/hnApi.ts
export const fetchItems = async (ids: number[]): Promise<HNItem[]> => {
return Promise.all(ids.map(id => fetchItem(id)));
};
2. Real-Time Polling: The "Live" Feel
One of the coolest features of HN 2026 is the real-time polling. In StoryDetail, I implemented an intelligent polling mechanism that adjusts its frequency based on activity.
// src/components/StoryDetail.tsx
useEffect(() => {
const loadStory = async (isUpdate = false) => {
const item = await fetchItem(id);
// If comment count changed, reset poll interval to aggressive
if (item.descendants !== story?.descendants) {
setPollInterval(30000);
} else {
// Back off if no changes are detected
setPollInterval(prev => Math.min(prev * 1.5, 300000));
}
setStory(item);
};
// ... polling logic
}, [id, pollInterval]);
3. The Global Theme System
I wanted users to have full control over their reading environment. I built a ThemeContext that manages both color themes (Light, Dark, Sepia, High Contrast) and typography (Sans, Serif, Outfit).
By injecting CSS variables into the root element, I can switch the entire app's look instantly without re-rendering the whole tree.
/* src/index.css */
[data-theme='sepia'] {
--color-theme-bg: #f4ecd8;
--color-theme-text: #5b4636;
--color-theme-muted: #8c7b6e;
}
4. Keyboard-First UX
For power users, I implemented keyboard shortcuts (J/K for navigation, Enter to open, B to bookmark). This required careful management of a selectedIndex state and ensuring the selected item is always scrolled into view.
// src/components/StoryList.tsx
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
switch (e.key.toLowerCase()) {
case 'j': setSelectedIndex(prev => Math.min(prev + 1, stories.length - 1)); break;
case 'k': setSelectedIndex(prev => Math.max(prev - 1, 0)); break;
// ... other keys
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [stories, selectedIndex]);
Challenges and Solutions
Challenge: Deeply Nested Comments
Hacker News comment threads can be incredibly deep.
Solution: I used a recursive Comment component with a depth prop to manage indentation and visual hierarchy. I also added a "Collapse All" feature to help users navigate massive threads.
Challenge: Performance with Infinite Scroll
Rendering hundreds of complex story cards can slow down the UI.
Solution: I implemented a simple but effective infinite scroll using IntersectionObserver and batch-fetched items to keep the main thread free.
Looking Ahead
Hacker News 2026 is just the beginning. I'm planning to add:
- Algolia Search: For finding historical discussions.
- PWA Support: For a native-like experience on mobile.
- User Mentions: To highlight relevant conversations.
Building this has been a journey in balancing minimalism with modern power. I hope you enjoy reading it as much as I enjoyed building it!
Check out the project on GitHub.
Inspired by https://x.com/MakerThrive/status/2035533184176144475







Top comments (0)