Adding Markdown Support for Blog Post Visitor Comments
Feb 5, 2025
I recently rebuilt this blog from scratch as a static site using Eleventy (11ty) as the static site generator and Netlify as my hosting service. A hand-written custom solution like this can be clean, well structured, easy to manage and as fast as you want (I'm now scoring 97-100 on the pagespeed test). This is the same solution I use when building websites for my clients, so it's about time my poor old blog gets a little TLC.
A basic feature I wanted for this blog was the ability for visitors to add comments to my posts. I documented how I solved this problem in great detail, but here's a high-level flow:
- A form was added to each blog post to capture data for a comment.
- A Netlify server-side function listens for form submission events. When a comment is added the function is triggered. The function validates the incoming form data, extracts key information from it like commenter name, website and the comment itself, merges it with existing comments for the site then opens a pull request in GitHub where the source for my static site resides.
- GitHub notifies me via a push notification (on my phone) and email that there's a new pull request. I review the pull request and either merge or deny it (if it's spam). Merging the pull request creates a new commit in the main branch.
- Netlify watches my GitHub commit history and triggers a new build and deploy of my site when a commit is received. Merging a comment into my repository triggers this process.
- Each blog post loads its data from an
11tydata
file, including post comments, and displays them to the user.
This process works great and visitors are able to leave comments (go ahead, I dare you!), but I wanted to level it up a bit by allowing visitors to style their comments with markdown.
Converting Comments from Markdown to HTML
In order for a comment containing markdown to be displayed properly on a website the markdown needs to be converted to HTML. For example, if a visitor leaves the comment:
## Hey!
This post is **great**!
The result as HTML would be:
<h2>Hey!</h2>
<p>This post is <strong>great</strong>!</p>
The form submission function created from the post I referenced before will be modified to handle this conversion process. For brevity, the following will contain only relevant snippets from this function, but you can reference the full function here:
A package called marked will be used to handle the conversion process. Install the marked
package in your project:
npm install -g marked
marked
exposes a function called parse
which takes raw markdown as input and returns raw HTML as output. Modify the function to pass the incoming comment (markdown or plain text) to the parse
:
import { parse } from "marked";
...
interface PostComment {
created_at: string;
data: PostCommentData;
}
interface PostCommentData {
name: string;
comment: string;
referrer: string;
website: string | undefined;
}
export default async (request: Request, context: Context) => {
try {
const postComment: PostComment = (await request.json()).payload;
// convert from markdown to html
const parsedComment = await parse(postComment.comment);
postData.comments.push({
...
html: parsedComment,
});
...
return new Response(`Thanks for commenting!`);
} catch (error) {
console.error(`An unexpected error occurred: ${JSON.stringify(error)}`);
return new Response(error.toString(), {
status: 500,
});
}
};
Now any comments flowing into this function will first be parsed to HTML before being sent to me for review via GitHub pull requests. Once the pull request is merged the HTML is stored in an 11tydata
file and loaded when the post loads. The comment itself is then rendered and styled accordingly, like so:
{% for comment in comments | reverse %}
<li>
<div class="content">
<p class="comment-name">
{{ comment.createdBy }}
</p>
<div class="bottom-wrapper">
<p class="comment-date">
{{ comment.date | postDate }}
</p>
<p class="comment-content">{{ comment.html | safe }}</p>
</div>
</div>
</li>
{% endfor %}
Comments
Leave a Comment