Skip to the solution
MediumMachine Coding9 min read

Build a Nested Comments widget

968 views

The problem

Question presented to candidate: "Build the comment section under a blog post. Comments can have replies, replies can have replies, with no fixed limit. I want to reply inline under any comment, collapse a thread to hide its replies, delete a comment together with everything under it, and add a new top-level comment."

Requirements:

  • Render nested comments recursively, each reply indented under its parent with a thread line.
  • Reply opens an inline textarea under that comment; Post is disabled while the text is empty or only spaces; Ctrl+Enter (or Cmd+Enter) posts; Escape or Cancel closes it.
  • Collapse / expand a thread with a toggle button that has aria-expanded; a collapsed comment shows how many replies are hidden.
  • Delete removes the comment and all its replies and announces how many were removed.
  • A header shows the total comment count; a top-level form adds a new thread.

What a strong answer should cover:

  • A recursive Comment component with a stable key per id and a depth for indentation.
  • Data vs UI state: the comment tree is data; "collapsed" and "replying" are per-comment UI state that can live in the component.
  • Immutable tree helpers by id (addReply, removeComment) or in-place mutation where the framework tracks it.
  • Counting a subtree recursively for the header and the "N replies hidden" note.
  • Accessibility: real buttons, aria-expanded, labelled textareas, a live status message.

Clarifying questions expected:

  • "Is there a maximum depth, or do we indent forever?"
  • "Should deleting keep a '[deleted]' placeholder when the comment has replies?"
  • "Are comments loaded all at once, or replies fetched on demand?"

Code / implementation expected: Yes. A working recursive widget with reply, collapse and delete.

  • React
  • Recursion
  • Tree

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

9 min read ยท 9 sections

React solution

Every file of the working solution. Open it in the playground to run and change it.

ReactComplete solution
import { useState } from "react";
import Comment from "./src/components/Comment";
import ReplyBox from "./src/components/ReplyBox";
import {
  initialComments,
  makeId,
  addReply,
  removeComment,
  countAll,
} from "./src/utils/comments";

export default function App() {
  const [comments, setComments] = useState(initialComments);
  const [status, setStatus] = useState("");

  function reply(parentId, text) {
    const comment = { id: makeId(), author: "You", text, replies: [] };
    setComments((list) => addReply(list, parentId, comment));
    setStatus(parentId ? "Reply posted" : "Comment posted");
  }

  function remove(comment) {
    const inside = countAll(comment.replies);
    setComments((list) => removeComment(list, comment.id));
    setStatus(
      "Deleted a comment" +
        (inside
          ? " and " + inside + (inside === 1 ? " reply" : " replies")
          : ""),
    );
  }

  const total = countAll(comments);
  return (
    <div className="app">
      <h1 data-testid="count">
        {total} {total === 1 ? "comment" : "comments"}
      </h1>
      <ReplyBox
        label="Add a comment"
        submitLabel="Comment"
        autoFocus={false}
        onSubmit={(t) => reply(null, t)}
      />
      <ul className="thread">
        {comments.map((c) => (
          <Comment
            key={c.id}
            comment={c}
            depth={0}
            onReply={reply}
            onDelete={remove}
          />
        ))}
      </ul>
      <p className="status" role="status" data-testid="status">
        {status}
      </p>
    </div>
  );
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 34 of 107 in Machine coding

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

Up nextMedium

Build Tic-Tac-Toe

Continue