Matt Hamlin
@matthamlin.me
`@hamstack/bluesky-embed-rsc`
A React Server Component for embedding @bsky.app posts!
bluesky-embed-rsc.vercel.app
Bluesky Embed RSC
Embed Bluesky posts in your app, with graceful fallbacks!
Embed Bluesky posts in your app, with graceful fallbacks!
Matt Hamlin
@matthamlin.me
Embed Bluesky posts in your app, with graceful fallbacks!
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
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>
);
}
tailwind
to look at node_modules
for the default styles to be applied.For Tailwind v3.x:
// In your tailwind config file:
content: [
"./node_modules/@hamstack/bluesky-embed-rsc/dist/**/*.js",
]
// In your tailwind config file:
content: [
"./node_modules/@hamstack/bluesky-embed-rsc/dist/**/*.js",
]
For Tailwind v4.x:
/* In your styles.css file: */
@source "./node_modules/@hamstack/bluesky-embed-rsc/dist/**/*.js";
/* In your styles.css file: */
@source "./node_modules/@hamstack/bluesky-embed-rsc/dist/**/*.js";
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
@matthamlin.me
@hamstack/bluesky-embed-rsc
provides the following exports:
BlueskyPostEmbed
- A server component that renders a Bluesky post embed
Props:
src: string
- The post URL to embed (this should follow the format of" "https://bsky.app/profile/{HANDLE}/post/{POST_ID}
)children?: ReactNode
- The optional fallback content if the post can't be loaded (this can be something custom - or it can be the embed blockquote from Bluesky)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: "",
};
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:
Matt Hamlin
@matthamlin.me
A (running) collection of Bluesky tips, tools, packages, and other misc things!