React

Using Behold with React JS

Add Instagram galleries to your React projects with our drop-in widget, or build your own UI with a JSON feed.

Behold React

Widget Component

The simplest way to get started is by using our official React Instagram widget component. This is a lightweight wrapper around our core web component, and let’s you drop an embedded widget right into your React code.

It has zero dependencies and is fully typed. Compatible with Next, Astro, Gatsby, Remix, etc.

Installation

First create a widget feed and copy the feedId from your widget embed code. Next, install with your package manager of choice.

Terminal window
npm install @behold/react
# or
pnpm add @behold/react
# or
yarn add @behold/react

After installing, simply import the component and use as normal.

import BeholdWidget from "@behold/react"
function MyComponent() {
return <BeholdWidget feedId="YOUR_FEED_ID" />
}

Configuration

The Behold React component has a single required property: feedId, which can be found by opening your widget feed in the Behold dashboard and clicking on Embed Code.

All configuration and customization is handled in the Behold admin. When you make changes there it will automatically update your widget, no code modifications required. Because of browser caching, changes can take a minute or two to show up. Clearing your cache and incognito/private windows will help.

Load event

You can optionally pass a callback function to the onLoad property, which will fire after initial render.

<BeholdWidget onLoad={() => console.log("Loaded!")} feedId="YOUR_FEED_ID" />

A note about SSR

This component relies on client-only APIs and won’t be pre-rendered by SSR or SSG. That means there will be a moment before it renders where its height will be 0px. You can prevent layout shifts this may cause by applying dimensions to a container element with CSS.

Custom implementation

To build your own custom UI, first create a JSON feed. Once you have a feed URL, just GET it and you’re off to the races.

Below is a simple, unstyled example to get you started. The full list of fields/data that are available can be found in our JSON feed docs.

import { useState, useEffect } from "react"
export default function InstaGallery({ feedId }) {
const [posts, setPosts] = useState([])
useEffect(() => {
const controller = new AbortController()
// Fetch feed, update state
async function fetchFeed() {
try {
// Fetch and parse feed
const rawFeed = await fetch(`https://feeds.behold.so/${feedId}`, {
signal: controller.signal,
})
// Pass http errors to the catch block
if (!rawFeed.ok) {
const errorMessage = await rawFeed.text()
throw new Error(errorMessage)
}
// Parse JSON
const feedJSON = await rawFeed.json()
// Update state with fetched posts
setPosts(feedJSON.posts)
} catch (err) {
// Swallow AbortErrors, since they are intentional and expected
if (err.name !== "AbortError") {
console.error("Error:", err)
}
}
}
// Run
fetchFeed()
// Abort fetch if feedId changes or component is unmounted
return () => {
controller.abort()
}
}, [feedId])
// Build post Els
const postEls = posts.map((post) => {
// IMAGE or CAROUSEL_ALBUM
let mediaEl = <img src={post.sizes.medium.mediaUrl} alt="" />
// VIDEO
if (post.mediaType === "VIDEO") {
mediaEl = (
<video
poster={post.sizes.medium.mediaUrl}
src={post.mediaUrl}
muted={true}
autoPlay={true}
loop={true}
></video>
)
}
return (
<figure key={post.id}>
{mediaEl}
<figcaption>{post.prunedCaption}</figcaption>
</figure>
)
})
return <div>{postEls}</div>
}
import type * as Behold from "@behold/types"
import { useState, useEffect } from "react"
export default function InstaGallery({ feedId }: { feedId: string }) {
const [posts, setPosts] = useState<Behold.Post[]>([])
useEffect(() => {
const controller = new AbortController()
// Fetch feed, update state
async function fetchFeed() {
try {
// Fetch and parse feed
const rawFeed = await fetch(`https://feeds.behold.so/${feedId}`, {
signal: controller.signal,
})
// Pass http errors to the catch block
if (!rawFeed.ok) {
const errorMessage = await rawFeed.text()
throw new Error(errorMessage)
}
// Parse JSON
const feedJSON: Behold.Feed = await rawFeed.json()
// Update state with fetched posts
setPosts(feedJSON.posts)
} catch (err) {
// Swallow AbortErrors, since they are intentional and expected
if (err.name !== "AbortError") {
console.error("Error:", err)
}
}
}
// Run
fetchFeed()
// Abort fetch if feedId changes or component is unmounted
return () => {
controller.abort()
}
}, [feedId])
// Build post Els
const postEls = posts.map((post) => {
// IMAGE or CAROUSEL_ALBUM
let mediaEl = <img src={post.sizes.medium.mediaUrl} alt="" />
// VIDEO
if (post.mediaType === "VIDEO") {
mediaEl = (
<video
poster={post.sizes.medium.mediaUrl}
src={post.mediaUrl}
muted={true}
autoPlay={true}
loop={true}
></video>
)
}
return (
<figure key={post.id}>
{mediaEl}
<figcaption>{post.prunedCaption}</figcaption>
</figure>
)
})
return <div>{postEls}</div>
}

Types

As a convenience we’ve published types for our JSON feeds. You can see an example of usage in the TS demo above.

Terminal window
# Install
npm install @behold/types
# or
pnpm add @behold/types
# or
yarn add @behold/types
// Import and apply
import type {
Feed,
Post,
ChildPost,
PostSizes,
PostSize,
ColorPalette,
RGBString,
} from "@behold/types"
const instaFeed: Feed = ...
// Import and apply
import type * as Behold from "@behold/types"
const instaFeed: Behold.Feed = ...

Ready to give it a try?

Sign up for free