Best for
Developers who need an image cropping widget inside a Next.js app — for avatar upload flows, profile picture editing, or content image preprocessing before upload to cloud storage
Stack
A ready-made Image Cropper UI you can fork, run, and customize with the prompt pack below.
What's actually inside
The honest engineer's breakdown — what the Image Croppertemplate does, how it's wired, and where it's opinionated.
The Image Cropper is a single-page Next.js app that handles the full client-side crop workflow without a backend. ImageUploadZone (powered by react-dropzone) accepts jpg, png, webp, and gif files via drag-and-drop or click-to-browse, validates type and size, and immediately renders the selected image for cropping. CropCanvas overlays react-image-crop's interactive crop box on the source image — the user drags to move it, uses corner handles to resize, and the crop state is managed as percentage-based coordinates that scale correctly regardless of display resolution.
AspectRatioControls provide one-click presets (1:1, 4:3, 16:9, 9:16, Free) that instantly constrain the CropCanvas selection. ZoomSlider increases the preview image scale for precise cropping of small regions. CropPreviewPanel shows a live thumbnail of the cropped area that updates as the crop box moves — essential feedback for avatar-style 1:1 crops. ExportControls let the user choose output format (JPEG/PNG/WebP), set JPEG quality (1–100), see a file size estimate, and download the result. The HTML5 Canvas API does the actual pixel-level crop: a drawImage() call with the precise crop coordinates from react-image-crop.
The honest caveat: the downloaded image can be blank or black on high-DPI screens if the template uses rendered display dimensions instead of natural image dimensions in the canvas drawImage() calculation. This is a very common react-image-crop gotcha and the fix is one line — see the gotchas section below. The template is otherwise genuinely beginner-friendly and the prompt pack extends it cleanly into a full avatar upload flow.
Key UI components
ImageUploadZonereact-dropzone area with MIME type and size validation and immediate image preview
CropCanvasreact-image-crop overlay with draggable crop box and corner resize handles
AspectRatioControlsPreset buttons (1:1, 4:3, 16:9, 9:16, Free) that constrain the CropCanvas selection
ZoomSliderScales the preview image for precise cropping of small areas
CropPreviewPanelLive thumbnail preview of the cropped area, updating in real time as the crop box moves
ExportControlsFormat selector (JPEG/PNG/WebP), quality slider, file size estimate, and Download button
Libraries it leans on
react-image-cropProvides the crop overlay UI, crop state management, and percentage-based crop coordinates
react-dropzoneFile selection and drag-and-drop with MIME type validation for ImageUploadZone
shadcn/uiSlider (zoom, quality), Button (aspect ratio presets, download), Badge (file size), Card
HTML5 Canvas APIRenders the final cropped image using drawImage() with react-image-crop's crop coordinates
Fork it and get it running
The cropper is fully client-side and needs zero backend to work. You can fork, verify, and publish in under five minutes — then layer on Supabase Storage if you need to persist the cropped images.
Fork the template into your V0 workspace
Navigate to https://v0.dev/chat/community/E3U776GJyyG in your browser. Click the 'Fork' button in the top-right corner of the chat. V0 copies the full template code into a new chat in your workspace. You need a free v0.dev account to fork.
Tip: 'Remix' and 'Fork' are the same action if V0 shows that label instead.
You should see: A new V0 chat opens with the image cropper code and a working Preview tab.
Drag a test image onto the ImageUploadZone in Preview
Open the Preview tab in the V0 editor. Find the ImageUploadZone and drag any jpeg or png file onto it. The source image should appear immediately, and a CropCanvas with a draggable crop selection box should overlay it. Drag the crop box and resize the corners to confirm the crop state updates and CropPreviewPanel shows the corresponding thumbnail.
Tip: If the crop overlay doesn't appear, react-image-crop's CSS may not have loaded — see the gotcha below.
You should see: Source image displays with a working interactive crop overlay and live preview thumbnail.
Test the aspect ratio presets and export
Click the 1:1 button in AspectRatioControls to lock the crop to a square. Adjust the crop box and watch it snap to equal width and height. Then open ExportControls, select JPEG at quality 80, and click the Download button. Open the downloaded file and confirm it contains only the cropped region at the correct dimensions.
Tip: If the downloaded image is blank or black, see the natural-vs-offset dimensions gotcha — this is the most common issue with this template.
You should see: Download button produces a correctly cropped JPEG of just the selected region.
Add Supabase env vars if you plan to upload cropped images
If you want the cropped output to go to cloud storage, open the Vars panel in V0 and add NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY. Both carry the NEXT_PUBLIC_ prefix because the Supabase JS client runs entirely in the browser for this use case. For the basic cropper with just download, you can skip this step entirely.
You should see: Storage credentials are saved in the Vars panel, ready for the Supabase upload prompt.
Publish to production
Click the Share button in the top-right of the V0 editor, then open the Publish tab and click 'Publish to Production'. Vercel builds and deploys in 30–60 seconds. If the react-image-crop CSS didn't load in Preview, the deployed version will almost always render correctly — the V0 Preview sandbox behaves differently from a real Next.js deployment.
You should see: A live Vercel URL serves the fully functional image cropper.
Export to GitHub for embedding in an existing project
Open the Git panel in V0 and click Connect. Enter a repo name and V0 creates a branch named v0/main-{hash}. Open the GitHub PR and merge it to main. The CropCanvas and ImageUploadZone components are self-contained enough to import directly into an existing Next.js app — for example, dropping them into an avatar upload dialog in a SaaS product.
Tip: Export early if you plan to embed this as a component rather than deploy it as a standalone page.
You should see: Code is on GitHub and ready to be imported into an existing Next.js project.
The prompt pack
Copy-paste these straight into v0's chat to customize the Image Croppertemplate. Each one names this template's own components — no generic filler.
Lock to 1:1 and round the CropPreviewPanel for avatar use
Converts the general-purpose cropper into a dedicated avatar upload widget with a circular preview that matches how most apps display profile photos.
Set the default aspect ratio in the CropCanvas react-image-crop configuration to 1 so it locks to a perfect square immediately on image load. Add CSS border-radius: 50% to CropPreviewPanel so the thumbnail appears as a circle, matching the typical avatar display shape. Rename the CropPreviewPanel label to 'Avatar Preview' and change the ExportControls Download button label to 'Download Avatar'. Also add a helper text line below the ImageUploadZone reading 'Drop a photo — recommended size 400x400px or larger'.
Add rotation controls to the CropCanvas toolbar
Adds rotate and flip controls so users can fix portrait photos taken sideways before cropping — a common need in mobile photo upload flows.
Add a RotationToolbar component directly below the CropCanvas with four icon buttons: rotate left (-90°), rotate right (+90°), flip horizontal, and flip vertical. Also add a free-angle slider from -45° to +45° for fine rotation. Apply the rotation and flip transforms to the canvas context before the drawImage() call in ExportControls: use ctx.translate(canvas.width/2, canvas.height/2), ctx.rotate(angleInRadians), then ctx.translate(-canvas.width/2, -canvas.height/2) before drawing. The CropPreviewPanel should also reflect the rotation in its live thumbnail.
Add image filters panel (brightness, contrast, saturation) before export
Lets users correct exposure and color balance directly in the cropper before downloading — eliminating the need for a separate photo editing step.
Add a FiltersPanel component with three shadcn Sliders: brightness (0–200, default 100), contrast (0–200, default 100), and saturation (0–200, default 100). Apply the current filter values as a CSS filter string to the source image element used in CropCanvas so users see the adjustment live. When the ExportControls Download button is clicked, apply the same filter values to the canvas rendering context using ctx.filter = 'brightness(B%) contrast(C%) saturate(S%)' before the drawImage() call so the downloaded file includes the filter. Add a Reset Filters button that returns all three sliders to 100.
Upload cropped image to Supabase Storage and return a public URL
Adds cloud persistence to the cropper so the output is both downloaded locally and uploaded to Supabase Storage with a shareable URL in one click.
After the user clicks the ExportControls Download button, also trigger a Supabase Storage upload in parallel. Convert the export canvas to a Blob using canvas.toBlob(blob => ..., 'image/jpeg', quality/100). Upload the blob to the 'avatars' Supabase Storage bucket using supabase.storage.from('avatars').upload(filename, blob, { contentType: 'image/jpeg', upsert: true }). Get the public URL with supabase.storage.from('avatars').getPublicUrl(filename). Display the URL in a new CopyableLink component below the ExportControls with a copy-to-clipboard button and a label 'Uploaded URL'. Use NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY from environment variables.Build a full avatar upload flow with Clerk auth and profile image update
Delivers a complete production avatar upload flow: auth gate, cloud storage, and live Clerk profile image update — all wired from the existing CropCanvas and ExportControls components.
Wrap the app in ClerkProvider using NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY. Use useAuth() to get the current userId and require sign-in before showing the ImageUploadZone. After cropping, upload the canvas blob to Supabase Storage at the path users/{userId}/avatar.jpg using the Supabase client with NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY. Then call a Server Action (marked with 'use server') that uses CLERK_SECRET_KEY (server-only, no NEXT_PUBLIC_ prefix) to update the user's profile image via fetch to https://api.clerk.com/v1/users/{userId}/profile_image with a multipart/form-data body. After the Server Action resolves, call useUser() to refresh the Clerk session and show the updated avatar in the header.Gotchas when you extend it
The failures people actually hit when they push this template past its defaults — and the exact fix for each.
Cropped image is blank or black on downloadWhy: The canvas drawImage() call uses the display (CSS-rendered) dimensions of the img element instead of its natural pixel dimensions. On high-DPI (Retina) screens or when the image is displayed smaller than its actual size, this produces wrong source coordinates and the canvas renders a black rectangle.
Fix: Replace img.offsetWidth and img.offsetHeight with img.naturalWidth and img.naturalHeight in the crop calculation. Scale the react-image-crop percentage-based crop values by the natural dimensions before passing them as the source rectangle to drawImage().
In the canvas export function, replace img.offsetWidth with img.naturalWidth and img.offsetHeight with img.naturalHeight when calculating the drawImage source rectangle
Missing @types/react-image-crop build error / TypeScript errors in CropCanvasWhy: V0 may install react-image-crop without its TypeScript type definitions, causing type errors on the Crop type import and the ReactCrop component props in CropCanvas.
Fix: Add @types/react-image-crop as a devDependency. In V0, prompt to add it to package.json devDependencies.
Add @types/react-image-crop to devDependencies in package.json to fix TypeScript errors in CropCanvas
react-image-crop overlay doesn't appear in V0 Preview — crop box is missingWhy: react-image-crop requires importing its CSS file (react-image-crop/dist/ReactCrop.css) for the crop overlay styles. This CSS import may not resolve correctly through esm.sh in the V0 preview sandbox, so the overlay renders invisible even though the component is mounted.
Fix: Add import 'react-image-crop/dist/ReactCrop.css' explicitly in the CropCanvas component file. If the V0 Preview still fails, click Publish to Production — the deployed Vercel environment handles CSS imports correctly.
Add import 'react-image-crop/dist/ReactCrop.css' to the CropCanvas component to ensure the crop overlay styles load
JPEG quality slider has no visible effect on the downloaded fileWhy: The quality slider state in ExportControls must be passed as the second argument to canvas.toDataURL('image/jpeg', quality/100). If the quality value is hardcoded elsewhere or the slider state is not threaded through to the toDataURL call, changing the slider does nothing to the output file size or quality.
Fix: Trace the quality Slider value from ExportControls state through to the canvas.toDataURL() call. Ensure the slider value (0–100 integer) is divided by 100 before passing it as the quality argument.
Connect the quality Slider value from ExportControls state to the canvas.toDataURL() second argument as quality/100
Template vs. custom — the honest call
A forked template gets you far, fast. Here's where it holds up, and where you'll outgrow it.
The template is enough when
- You need an avatar or profile photo upload flow with in-browser cropping before Supabase Storage upload
- You're building a CMS where editors crop and resize images before publishing to a content bucket
- Your cropping requirements are standard — aspect ratio presets, zoom, format selection, and download
- You need a self-contained crop widget you can embed in an existing dialog or modal in a week
Go custom when
- You need server-side image processing with auto-resize, WebP conversion, and CDN delivery at scale
- You need face detection to auto-center the crop box on portraits without manual adjustment
- You need batch cropping for multiple images simultaneously with a queue and progress tracking
- You need a full image editing suite beyond crop — background removal, text overlays, multi-layer compositing
RapidDev can wire this cropper to Supabase Storage with auto-resize on the server side and CDN delivery — a common pattern we implement for SaaS avatar and media upload flows.
Frequently asked questions
Is the Image Cropper template free to use?
Yes. All v0.dev community templates are free to fork with a free v0.dev account. There are no fees for the template itself. If you add Supabase Storage for cloud upload, costs depend on your Supabase plan — the free tier includes 1GB of storage.
Can I use this template commercially?
Yes. V0 community templates are permissively licensed for commercial use. The libraries included — react-image-crop, react-dropzone, and shadcn/ui — are all MIT licensed. You can embed this cropper in a commercial SaaS product or client project without attribution requirements.
Why does the crop overlay disappear or not show in the V0 Preview?
react-image-crop requires its CSS file (react-image-crop/dist/ReactCrop.css) to be imported for the overlay to render. In V0's Preview sandbox the CSS import may not resolve via esm.sh. Add import 'react-image-crop/dist/ReactCrop.css' explicitly in CropCanvas. If the Preview still doesn't show it, click Publish to Production — the deployed Vercel environment resolves CSS imports correctly.
Do I need a backend or database to use this template?
No. The base template is 100% client-side. Uploading, cropping, and downloading all run in the browser using react-image-crop and HTML5 Canvas with no API calls. Add Supabase Storage only if you want the cropped image to persist in the cloud — the 'Upload to Supabase Storage' prompt in the pack above adds that in one step.
Why is my downloaded cropped image blank or completely black?
This is the most common bug with react-image-crop in Next.js. The canvas drawImage() call is using the displayed (CSS) pixel dimensions of the image instead of its actual natural pixel dimensions. Fix: replace img.offsetWidth with img.naturalWidth and img.offsetHeight with img.naturalHeight in the canvas export function, then scale the percentage-based crop coordinates by the natural dimensions.
How do I lock the crop to a circle for avatar use?
Use the '1:1 avatar mode' prompt from the pack above. It sets react-image-crop's aspect prop to 1 (perfect square) and adds border-radius: 50% to CropPreviewPanel so the thumbnail looks circular. The downloaded image is still a square PNG — apply the circle clip in CSS wherever you display the avatar, which is the standard pattern for SaaS apps.
Can RapidDev build a complete avatar upload flow with this template?
Yes. RapidDev implements Supabase Storage-backed avatar flows with server-side resize and CDN delivery as a standard pattern for SaaS products — typically on top of v0 prototypes like this one. Reach out for a scoping call.
The JPEG quality slider does nothing — the file size stays the same. Why?
The quality slider value is probably not connected to the canvas.toDataURL() call. The second argument to toDataURL('image/jpeg', q) must receive your slider value divided by 100 (so a 80% slider = 0.8). Trace the slider state through to the export function and verify the division is applied before passing it to toDataURL.
Outgrowing the template?
RapidDev turns v0 prototypes into production apps — real auth, database, and payments — at $13K–$25K.
Book a free consultation30-min call. No commitment.