System Design

How would you design system a frontend like Trello?

I've used Trello for years. What makes it feel great isn't the feature list — it's the interaction model. Drag a card, drop it in another list, and everyt...

8 May 2024

How would you design system a frontend like Trello?

I've used Trello for years. What makes it feel great isn't the feature list — it's the interaction model. Drag a card, drop it in another list, and everything updates instantly. No page reload. No loading spinner. No lag. That fluid interaction is the frontend system design challenge.

Building a Trello clone that looks right takes a day. Building one that feels right takes weeks. Here's why.

The Layout Model: Boards, Lists, Cards

Trello's UI is a nested hierarchy:

  • Boards are the top-level containers. Each board represents a project or workspace.
  • Lists are columns within a board. They represent stages (To Do, In Progress, Done) or categories.
  • Cards are items within lists. Each card represents a task with details: description, due date, labels, attachments, comments, and assignees.

This three-level hierarchy needs to render efficiently. A busy board might have 10 lists with 50 cards each. That's 500 DOM elements just for cards, plus metadata, labels, and avatars. Virtual scrolling or lazy rendering matters for performance.

Drag and Drop: The Hard Part

Drag and drop looks simple. It's not. The challenges:

Smooth visual feedback. The dragged card must follow the cursor precisely. Other cards must animate out of the way in real-time. The drop target must be visually obvious.

State management during drag. While dragging, you need to track: the source list, the source position, the current hover target, and the drop position. If the user moves between lists, the card preview must jump between them.

Optimistic updates. When a card is dropped, update the UI immediately. Don't wait for the server response. If the server rejects the move (permissions, conflict), revert the UI. Users expect instant feedback.

Persistence. After a drop, send the new card position to the backend. The backend must handle the ordering (position column with fractional values or array reordering).

I use libraries like @dnd-kit or react-beautiful-dnd for the heavy lifting. Building drag-and-drop from scratch with raw pointer events is possible but error-prone — especially across browsers and touch devices.

Real-Time Collaboration

Multiple users editing the same board simultaneously. This requires:

WebSocket connection for live updates. When User A moves a card, User B's board updates instantly.

Conflict resolution. Two users drag the same card to different lists at the same moment. Who wins? Most Trello-like apps use last-write-wins with optimistic updates. The second user sees their card "jump" to the other user's chosen list after a brief moment. It's not perfect, but it's simple and works for most cases.

Presence indicators. Show which users are currently viewing the board. Show cursor positions or active card edits. This reduces conflicts because users can see where others are working.

Search and Filtering

Users with 50 boards and hundreds of cards need to find things fast:

  • Global search across all boards, lists, and cards. Search by title, description, labels, and assignees.
  • Board-level filters — filter cards by label, due date, assignee, or custom fields. Filters should be instant (client-side for the current board's data).
  • Keyboard shortcuts — power users navigate entirely by keyboard. n for new card, / for search, arrow keys for navigation.

Notifications

Keep users informed without overwhelming them:

  • Activity feed — show recent changes to boards and cards the user follows.
  • Due date reminders — push notifications and in-app alerts for approaching or overdue deadlines.
  • @mentions — notify users when they're mentioned in card comments.
  • Customizable settings — let users control notification frequency and channels (email, push, in-app).

Accessibility

This is often neglected in drag-and-drop interfaces:

  • Keyboard-driven drag and drop — let users select a card with Enter, move it with arrow keys, and drop it with Enter. This is required for screen reader users.
  • ARIA labels — announce card position, list name, and available actions.
  • Focus management — after a card move, focus should land on the moved card in its new position.
  • Color contrast — labels, buttons, and status indicators must meet WCAG AA contrast ratios.

The Trade-Offs

Client-side state vs. server state. Keep a local copy of the board state for instant UI updates. Sync with the server in the background. The trade-off is complexity: you need to handle conflicts, retries, and stale data. But the UX improvement is worth it.

Real-time updates vs. bandwidth. WebSocket connections for every board viewer use server resources. For boards with few active users, long polling is cheaper. For busy boards with many editors, WebSockets are essential.

Feature richness vs. simplicity. Trello's strength is simplicity. Adding too many features (Gantt charts, time tracking, dependencies) turns it into Jira. The design tension is keeping the core interaction (boards, lists, cards, drag and drop) fast and simple while allowing power features through extensions or integrations.

Library vs. custom drag-and-drop. Libraries save development time but add bundle size and constrain customization. Custom implementations give full control but take weeks to get right across browsers and devices. I start with a library and only go custom if the library can't handle a specific interaction.

The best Trello-like frontends feel like direct manipulation — you're moving physical cards on a physical board. Every millisecond of lag, every visual glitch, every unexpected behavior breaks that illusion. The engineering challenge is maintaining that illusion at scale.