How I Made Comments Component for My Blog Posts | Philip Wallis
Comments
How I Made Comments Component for My Blog Posts
March 26, 2025
If you are reading this, you probably like getting feedback for your work. For a blog-specific use case, comments are something that can bring in feedback easily. In this post I will talk about how I implemented it for my own website.
This is an important step if you want to have any kind of protection. Although minimal, I have an auth wall to stop people from just spamming the api. I am using here, and you can probably use any auth system you would like.
I currently only allow sign ins from Google OAuth, and this probably discourages people who want to stay anonymous to comment on my posts. This is a trade-off that I believe would be better in the long run for my portfolio website, because it filters out comments that are fully anonymous.
For my portfolio website, I am using to handle my database. Here is what my comments schema looks like:
typescript
exportconst comments =createTable("comment",{
id:varchar("id",{ length:255}).notNull().primaryKey().$defaultFn(()=> crypto.randomUUID()),
content:text("content").notNull(),
postSlug:varchar("post_slug",{ length:255}).notNull(),
userId:varchar("user_id",{ length:255}).notNull().references(()=> users.id,{ onDelete:"cascade"}),
parentId:varchar("parent_id",{ length:255}),// No direct reference here
createdAt:timestamp("created_at",{ withTimezone:true}).default(sql`CURRENT_TIMESTAMP`).notNull(),
updatedAt:timestamp("updated_at",{ withTimezone:true}).$onUpdate(()=>newDate()),
isDeleted:boolean("is_deleted").default(false).notNull(),},(comment)=>({
userIdIdx:index("comment_user_id_idx").on(comment.userId),
postSlugIdx:index("comment_post_slug_idx").on(comment.postSlug),
parentIdIdx:index("comment_parent_id_idx").on(comment.parentId),}));
Two things that I want to talk about here is the parentId and isDeleted columns.
I intentionally designed parentId without a direct foreign key constraint to avoid any referential constraints on replies. By omitting the direct reference, I gained flexibility to handle comment hierarchies, including scenarios involving soft-deleted parent comments.
The isDeleted boolean column implements a soft delete strategy, which means I am marking the comment as deleted, rather than deleting the row from the database. The advantages to this is that I can keep the comment thread's structural integrity, as well as maintaining historical context for nested replies. This also prevents cascaded deletion issues when a comment with replies is deleted. One thing that I would like to add in the future is in cases where there are no replies or all replies are also deleted, I fully delete the thread from the database. This can probably be done during deletion by checking if all parent/child/sibling comments are also soft deleted.
slug here is used to pass to the database to store the specific post the comment is made under, and session is used to authenticate the user.
You can scroll down to see what the comments look like! Most of the UI is written using shadcn and a little bit of AI.
typescript
const shouldShowThread =(comment: Comment):boolean=>{// If the parent comment is not deleted, we should always show the threadif(!isCommentDeleted(comment))returntrue;// If parent is deleted, check if any replies exist and are not deletedif(comment.replies && comment.replies.length >0){return comment.replies.some((reply: Comment)=>!isCommentDeleted(reply));}// Parent is deleted and no replies or all replies are deletedreturnfalse;};
Remember soft-deleting the comments in the database? This helper function is used to determine which comments will be rendered to the user.
Building a comments component for my blog has been an interesting learning experience. The implementation combines authentication, database design, and React components to create a functional commenting system that allows readers to engage with my content.
If you're building your own blog or content platform, I hope this breakdown of my comment system implementation helps you create something that works for your specific needs. Comments are a valuable way to build community around your content and receive direct feedback from readers.
Feel free to leave a comment below if you have any questions or suggestions about this implementation!
Comments