Elements

Pre-built React components for common patterns when working with Stack0. Copy, paste, and customize.

Installation

Choose your preferred installation method:

Recommended: shadcn CLI

Copy components directly into your project with full customization control:

terminal
npx shadcn@latest add https://www.stack0.dev/r/file-upload
npx shadcn@latest add https://www.stack0.dev/r/avatar-upload
npx shadcn@latest add https://www.stack0.dev/r/logo-upload
npx shadcn@latest add https://www.stack0.dev/r/image-gallery
npx shadcn@latest add https://www.stack0.dev/r/image

Alternative: NPM Package

terminal
# Install the package
npm install @stack0/elements
# Or with pnpm
pnpm add @stack0/elements
# Or with bun
bun add @stack0/elements

Required peer dependencies:

terminal
npm install class-variance-authority clsx tailwind-merge lucide-react

Stack0 Integration

Elements work with any upload backend. Create an API endpoint on your server that returns presigned URLs, then use the handler on the client:

client.tsx
// Client-side usage
import { FileUpload, createStack0Handler } from '@stack0/elements'
const handler = createStack0Handler({
endpoint: '/api/upload', // Your API endpoint
})
<FileUpload handler={handler} />
app/api/upload/route.ts
// Server-side API route (Next.js App Router)
// app/api/upload/route.ts
import { stack0 } from '@stack0/sdk'
export async function POST(request: Request) {
const { filename, mimeType, size, folder } = await request.json()
const result = await stack0.cdn.createUpload({
filename,
mimeType,
size,
folder,
public: true, // Creates a public presigned URL
})
return Response.json({
uploadUrl: result.uploadUrl,
assetId: result.assetId,
})
}

Custom Handlers

Create your own upload handler for any backend:

custom-handler.tsx
import { FileUpload, type UploadHandler } from '@stack0/elements'
const customHandler: UploadHandler = {
// Get a presigned URL for uploading
getUploadUrl: async (file) => {
const response = await fetch('/api/upload', {
method: 'POST',
body: JSON.stringify({
filename: file.name,
mimeType: file.type,
size: file.size,
}),
})
const data = await response.json()
return {
uploadUrl: data.uploadUrl,
assetId: data.assetId,
}
},
// Called after upload completes (optional)
onUploadComplete: async (assetId, file) => {
await fetch(`/api/upload/${assetId}/confirm`, { method: 'POST' })
return { url: `https://cdn.example.com/${assetId}` }
},
// Handle errors (optional)
onError: (error, file) => {
console.error(`Upload failed for ${file.name}:`, error)
},
}
<FileUpload handler={customHandler} />

Styling & Theming

Elements use CSS variables compatible with shadcn/ui. Make sure your project has these variables defined:

globals.css
/* In your global CSS */
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
/* ... other variables */
}

Copy Individual Elements

Each element page includes the full source code that you can copy directly into your project. This gives you full control to customize the elements to your needs.