In the ever-evolving world of social media, Bluesky has emerged as an exciting decentralized alternative to traditional platforms. As a developer passionate about creating interactive web experiences, I set out to build a custom web component that could seamlessly integrate Bluesky post comments into any website.
Credits
This project was started by Emily Liu, who came up with the idea of using a Bluesky thread as a comments thread. Cory Zue expanded on the idea by removing lots of NextJS dependencies. However it still required a lot of React dependencies, which was why I started creating a web component based version. Lots of developers use static sites for blogs, this works great for static sites, reducing the JS size by 98.5%!
The Motivation
Web components offer a powerful way to create reusable, encapsulated UI elements. My goal was to create a simple, lightweight component that could:
- Fetch comments for a specific Bluesky post
- Render comments in a clean, readable format
- Provide a customizable and lightweight solution for embedding discussions
Key Technical Challenges
1. Fetching Comments via Bluesky's Public API
The first hurdle was interfacing with Bluesky's public API. The fetchThread method became the cornerstone of the component:
async fetchThread(uri) {
const url = `https://public.api.bsky.app/xrpc/app.bsky.feed.getPostThread?uri=${encodeURIComponent(uri)}`;
const response = await fetch(url, {
method: "GET",
headers: { Accept: "application/json" },
cache: "no-store"
});
if (!response.ok) {
throw new Error(`Failed to fetch thread: ${response.statusText}`);
}
return await response.json();
}2. Creating a Flexible Rendering Approach
The render method had to be both powerful and flexible. I implemented a sorting mechanism to prioritize high-engagement comments and added a "Show more" functionality:
render() {
const sortedReplies = this.thread.replies.sort(
(a, b) => (b.post.likeCount ?? 0) - (a.post.likeCount ?? 0)
);
// Render initial comments and provide expand functionality
sortedReplies.slice(0, this.visibleCount).forEach((reply) => {
commentsContainer.appendChild(this.createCommentElement(reply));
});
}3. Security and Styling Considerations
I implemented several key features to ensure security and flexibility:
- HTML escaping to prevent XSS attacks
- CSS custom properties for easy theming
- Shadow DOM for style encapsulation
Lessons Learned
- API Interaction: Working with public APIs requires robust error handling and flexible parsing.
- Web Components: They provide an elegant way to create reusable, framework-agnostic UI elements.
- Performance: Implementing features like lazy loading helps manage larger comment threads.
Code Highlights
The component uses several modern web APIs:
CustomElementRegistryfor defining the web component- Shadow DOM for style encapsulation
fetchfor API interactions
Customization Options
The component supports several customization methods:
no-cssattribute to disable default styling- CSS custom properties for theming
- Configurable number of initial comments
Future Improvements
While the current implementation is functional, there's room for enhancement:
- Add date/timestamp to comments
- Implement nested comment threading
- Add user interaction features like liking or replying
Conclusion
Building this Bluesky comments web component was an exciting journey into modern web development. It demonstrates the power of web components in creating modular, reusable UI elements that can work across different frameworks and websites.
Usage Example
<bsky-comments post="at://did:plc:user/collection/postid"></bsky-comments>By leveraging web standards and Bluesky's public API, we've created a simple yet powerful way to embed social discussions into any web page.