Integrate replies to a specific Bluesky post directly into your website or blog articles. This widget fetches the comment thread for a given post and displays it, allowing readers to see the conversation happening on Bluesky without leaving your site.

Features

  • Embed Bluesky Replies: Show the discussion from a Bluesky post thread with correct visual nesting.
  • Parent Post Stats: Displays likes, reposts, replies, and quotes for the original post (hides stats with zero count), linked to Bluesky where applicable.
  • No Authentication Required: Uses the public Bluesky API.
  • Simple Integration: Add a div and a small JavaScript snippet to your HTML.
  • Controls: Includes options to sort and search comments.
  • Clickable Comments: Entire comment bodies link back to the original reply post on Bluesky.
  • Customizable: Don't like the design? Style the widget using bluesky-comments.css.
  • Dependency: Uses Phosphor Icons (linked via CDN).

How to Use

  1. Get the Files: Download bluesky-comments.js and bluesky-comments.css. Place them in your website's project folder (e.g., js/ and css/).
  1. Link Files in HTML: In the <head> of your HTML, link the CSS files. Load bluesky-comments.css AFTER any general stylesheets (like style.css) if you encounter styling conflicts.
<head>
    <link rel="stylesheet" href="path/to/your/css/style.css"> <!-- Your general styles -->
    <link rel="stylesheet" href="path/to/your/css/bluesky-comments.css"> <!-- Widget styles -->
    <link rel="stylesheet" type="text/css" href="https://unpkg.com/@phosphor-icons/web@2.1.1/src/duotone/style.css" />
</head>

Before the closing </body> tag, link the JavaScript file:

<body>
    <script src="path/to/your/js/bluesky-comments.js"></script>
    <!-- Initialization script below -->
</body>

(Update path/to/your/css/ and path/to/your/js/)

  1. Add the Container: Place this empty div in your HTML where the comments should appear. Give it a unique ID.
<div id="my-bluesky-comments">
    <p><i>Loading Bluesky comments...</i></p>
</div>
  1. Initialize the Widget: Add the following <script> block after including bluesky-comments.js (usually just before </body>). Update targetContainerId and blueskyPostUri below.
<script>
    document.addEventListener('DOMContentLoaded', function () {
        const targetContainerId = 'my-bluesky-comments';
        const blueskyPostUri = 'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3lktlkvn2lc2k'; // <<<--- CHANGE THIS URI
        if (typeof loadAndRenderComments === 'function') {
            loadAndRenderComments(targetContainerId, blueskyPostUri);
        } else {
            console.error("Error: loadAndRenderComments function not found.");
            const container = document.getElementById(targetContainerId);
            if (container) {
                container.innerHTML = '<p class="bsky-comments-error">Error: Could not load comments component.</p>';
            }
        }
    });
</script>

Customization

  • Styling: Modify bluesky-comments.css (CSS variables are available at the top).
  • Behavior: Adjust constants like BSKY_MAX_INITIAL_COMMENTS, BSKY_COMMENTS_INCREMENT, or BSKY_INDENT_SIZE_PX in bluesky-comments.js.

Dependencies

Sample HTML Template

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Bluesky Comments Widget Example</title>

    <!-- Link to the widget's CSS file (in the same directory) -->
    <link rel="stylesheet" href="bluesky-comments.css">

    <!-- Link to Google Fonts (optional, but used by the CSS) -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link
        href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap"
        rel="stylesheet">

    <!-- Link to Phosphor Icons CSS (required for icons) -->
    <link rel="stylesheet" type="text/css" href="https://unpkg.com/@phosphor-icons/web@2.1.1/src/duotone/style.css" />
</head>

<body>
    <div class="widget-wrapper">
        <div id="bluesky-comment-widget">
            <!-- Initial placeholder message -->
            <p><i>Loading Bluesky comments...</i></p>
        </div>
    </div>
    <!-- Include the widget's JavaScript file (in the same directory) -->
    <!-- IMPORTANT: Load this script AFTER the container div -->
    <script src="bluesky-comments.js"></script>
    <!-- Initialize the script -->
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            // --- Configuration ---
            // 1. ID of the container div above. MUST match.
            const targetContainerId = 'bluesky-comment-widget';

            // 2. AT URI of the Bluesky post to display replies from.
            //    Find via post options (...) > Copy link to post > extract 'at://...' part.
            const blueskyPostUri = 'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3lktlkvn2lc2k';
            // 3. Load the comments.
            if (typeof loadAndRenderComments === 'function') {
                loadAndRenderComments(targetContainerId, blueskyPostUri);
            } else {
                console.error("Error: loadAndRenderComments function not found. Ensure bluesky-comments.js is loaded correctly and before this script block.");
                const container = document.getElementById(targetContainerId);
                if (container) {
                    container.innerHTML = '<p class="bsky-comments-error" style="padding:1em; text-align:center;">Error: Could not load comments component JavaScript.</p>';
                }
            }
        });
    </script>
</body>

</html>

I'm not a coder. I use LLMs like Claude, Mistral, Meta AI, ChatGPT, and Gemini to create things that fit what I need. I share them so others can use them too. The code may not follow standard rules, so if you're a developer and see ways to make it better, I'd really appreciate your help.