The ActionImageBrowser
component is a plugin for the ActionImage
component. It allows you to select images from a list of images. We can use it to build a custom image browser plugin.
In the following example, we'll build a meme browser plugin. We'll use the Imgflip API to fetch memes.
Download the Starter Template
We'll start by downloading the starter template.
Add License Key
Add your LICENSE KEY to the package.json
file:
"@shadcn/designer": "https://ds.shadcn.com/registry?license=YOUR_LICENSE_KEY&version=0.4.2",
Install Dependencies
Install the dependencies by running the following command:
pnpm install
Update the frame size
Let's update the example post frameSize to 1080x1080 which works better for memes.
import { Layer } from "@shadcn/designer"
export async function getPost() {
return {
id: "xg9x0ff27hx09n0d",
title: "Untitled Post",
layers: [
{
id: "xqxbjdzdjyz",
name: "Image",
type: "image",
value: "https://images.unsplash.com/photo-1503023345310-bd7c1de61c7d",
cssVars: {
"--width": "1080px", // <--- Update this
"--height": "1080px", // <--- Update this
"--z-index": "0",
"--translate-x": "0px",
"--translate-y": "0px",
},
},
],
meta: {
frameSize: {
width: 1080, // <--- Update this
height: 1080, // <--- Update this
},
},
}
}
If you visit http://localhost:3000
you should see the following:

Add a Meme Browser
Let's add our meme browser to the ActionImage
component. We can use the ActionImageBrowser
component to build our meme browser.
In components/editor.tsx
, find the PanelRight
component and add the following to ActionImage
component:
<ActionImage
plugins={[
// ... other plugins
{
id: "meme-browser",
label: "Meme Browser",
description: "Select a meme from the browser.",
component: (
<ActionImageBrowser
apiUrl="/api/memes"
/>
),
},
]}
/>
If you select an image layer and click the Image button in the right panel, you should see a new Meme Browser tab in the image dialog.
Build our API route
The ActionImageBrowser
component requires an API route to fetch the images. We'll create a simple API route to fetch memes from the imgflip API.
import { NextRequest, NextResponse } from "next/server"
import { imagesResponseSchema } from "@shadcn/designer/schema"
const DEFAULT_QUERY = "Pikachu"
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url)
const query = searchParams.get("query") || DEFAULT_QUERY
const page = Number(searchParams.get("page")) || 1
const per_page = Number(searchParams.get("per_page")) || 9
const url = `https://api.imgflip.com/get_memes`
const response = await fetch(url)
const data = await response.json()
// Imgflip does not have pagination.
// We'll implement a faux pagination and search.
const startIndex = (page - 1) * per_page
const endIndex = startIndex + per_page
const memes = data.data.memes.filter((meme: { name: string }) =>
meme.name.toLowerCase().includes(query.toLowerCase())
)
const thisPage = memes.slice(startIndex, endIndex)
return NextResponse.json(
imagesResponseSchema.parse({
results: thisPage.map((meme: { id: string; url: string }) => ({
id: meme.id,
url: meme.url,
thumbnailUrl: meme.url,
})),
total: memes.length,
total_pages: Math.ceil(memes.length / per_page),
})
)
}
To make sure we return the correct data structure, we'll use the imagesResponseSchema
from the @shadcn/designer/schema
package.
That's it!
That's all you need. You can now select an image, open the image dialog, search and apply a meme to the layer.