Bluesky Embed RSC

Embed Bluesky posts in your app, with graceful fallbacks!

Installation

Install @hamstack/bluesky-embed-rsc via your favorite package manager:


# Install the library and it's peer dependencies
bun install @hamstack/bluesky-embed-rsc \
  @atcute/bluesky \
  @atcute/lexicons \
  @atcute/client \
  @atcute/bluesky-richtext-segmenter \
  hls.js \
  @radix-ui/react-aspect-ratio \
  clsx \
  tailwind-merge \
  lucide-react
                

# Install the library and it's peer dependencies
bun install @hamstack/bluesky-embed-rsc \
  @atcute/bluesky \
  @atcute/lexicons \
  @atcute/client \
  @atcute/bluesky-richtext-segmenter \
  hls.js \
  @radix-ui/react-aspect-ratio \
  clsx \
  tailwind-merge \
  lucide-react
                

Usage:

Here's an example of how to set this up with Next.js:

import { BlueskyPostEmbed } from "@hamstack/bluesky-embed-rsc";

export default function Home() {
  return (
    <BlueskyPostEmbed src="https://bsky.app/profile/matthamlin.me/post/3layiwns2kk2h">
      This post could not be loaded!
    </BlueskyPostEmbed>
  );
}
import { BlueskyPostEmbed } from "@hamstack/bluesky-embed-rsc";

export default function Home() {
  return (
    <BlueskyPostEmbed src="https://bsky.app/profile/matthamlin.me/post/3layiwns2kk2h">
      This post could not be loaded!
    </BlueskyPostEmbed>
  );
}

The BlueskyPostEmbed component will render the post, or fallback content if the post can't be loaded.

Here's what the output looks like:

Matt Hamlin

Matt Hamlin

@matthamlin.me

Beer and a fish finger sandwich with chips 🙌
Two glasses of beer on a table in a pub
a fish finger sandwich with a small bowl of chips
6 months agoView on bsky.app
4
10
0
0

Exports:

@hamstack/bluesky-embed-rsc provides the following exports:

Additionally, a updateConfig function is exported to update the configuration at runtime. This can be useful if you want to customize the various icons or components used inside the embed!

import { updateConfig } from "@hamstack/bluesky-embed-rsc";
import {
  HeartIcon,
  LinkIcon,
  MessageCircleIcon,
  QuoteIcon,
  RepeatIcon,
} from "your-favorite-icon-library";
import Image from "your-favorite-image-library";

// customize the Image component, or the icons used in the embed
updateConfig({
  components: {
    Image: Image,
    // can also pass:
    // Video - used for rendering videos
    // External - used for rendering website previews/embeds
  },
  icons: {
    Heart: HeartIcon,
    Link: LinkIcon,
    MessageCircle: MessageCircleIcon,
    Quote: QuoteIcon,
    Repeat: RepeatIcon,
  },
  // can also pass in `linkClassName` to customize the link styles
  rootClassName: "my-2 mx-auto",
});
import { updateConfig } from "@hamstack/bluesky-embed-rsc";
import {
  HeartIcon,
  LinkIcon,
  MessageCircleIcon,
  QuoteIcon,
  RepeatIcon,
} from "your-favorite-icon-library";
import Image from "your-favorite-image-library";

// customize the Image component, or the icons used in the embed
updateConfig({
  components: {
    Image: Image,
    // can also pass:
    // Video - used for rendering videos
    // External - used for rendering website previews/embeds
  },
  icons: {
    Heart: HeartIcon,
    Link: LinkIcon,
    MessageCircle: MessageCircleIcon,
    Quote: QuoteIcon,
    Repeat: RepeatIcon,
  },
  // can also pass in `linkClassName` to customize the link styles
  rootClassName: "my-2 mx-auto",
});

The default config is:

export let config: Config = {
  components: {
    // Custom Image, Video, and External components
    Image,
    Video,
    External,
  },
  icons: {
    // Icons from lucide-react
    Heart,
    Link: LinkIcon,
    MessageCircle,
    Quote,
    Repeat,
  },
  linkClassName: "",
  rootClassName: "",
};
export let config: Config = {
  components: {
    // Custom Image, Video, and External components
    Image,
    Video,
    External,
  },
  icons: {
    // Icons from lucide-react
    Heart,
    Link: LinkIcon,
    MessageCircle,
    Quote,
    Repeat,
  },
  linkClassName: "",
  rootClassName: "",
};

Features:

The BlueskyPostEmbed component is a server component, so it can be used in any React Server Component compatible framework (e.g. Waku, Parcel, Redwood SDK, Next etc.).

The component will render the post, or fallback content (see the children prop) if the post can't be loaded.

Additionally, the component will "expand" (e.g. render inline previews) post embeds, currently limited to images, videos, and external links!

Here's an example post that shows an embedded preview to another website: