Desktop Pricing Docs Blog About GitHub Get started

Add image upload to your Lexical editor in one prompt

Lexical is a contenteditable editor, so it uses PixelVault's upload helper rather than the textarea widget. This prompt wires paste + drop to upload images and insert them as image nodes — no upload backend. Copy it into your AI coding agent.

Works with Claude CodeCursorWindsurfCopilot
  1. 1
    Copy the prompt

    The one big button below.

  2. 2
    Paste it into your agent

    In your project — Claude Code, Cursor, etc.

  3. 3
    Drop in your key

    Swap pv_pub_REPLACE_ME for a free key. Done.

Prompt for your coding agent
Add image paste-and-host to my Lexical editor using PixelVault.

Context — read this first and use only the documented API:
- Overview + API: https://pixelvault.dev/llms.txt
- PixelVault upload helper (from @pixelvault-dev/paste):
    import { uploadImage } from "@pixelvault-dev/paste";
    const { url } = await uploadImage(file, { publishableKey: "pv_pub_REPLACE_ME" });
    // returns { id, url, mimeType, size }; throws PixelVaultPasteError on failure

Important: Lexical is a contenteditable editor, not a <textarea>, so do NOT use
the paste-react/usePaste widget here — use uploadImage() directly.

Do this:
1. Install: npm install @pixelvault-dev/paste

2. Make sure my editor has an image node registered. Lexical core ships NO
   built-in image node — if my editor doesn't already have one (e.g. the
   Lexical playground's ImageNode), STOP and tell me, because I need one before
   this can insert images.

3. Register a Lexical handler for pasted/dropped image files. The idiomatic hook
   is the DRAG_DROP_PASTE command from @lexical/rich-text:
     editor.registerCommand(DRAG_DROP_PASTE, (files) => { ...; return true; }, COMMAND_PRIORITY_LOW)
   which fires with the dropped/pasted File(s). For each image file: call
   uploadImage(file, { publishableKey }), and on success insert my image node
   with the returned url inside an editor.update() block. Don't await inside the
   command handler — kick off the async upload and return true. Show a fallback
   if the upload throws PixelVaultPasteError.

4. Use my publishable key where I wrote pv_pub_REPLACE_ME (I'll paste my own).

Rules:
- For the PixelVault part, use ONLY uploadImage(file, options) as documented above —
  do NOT invent PixelVault endpoints, options, or other packages.
- Use Lexical's own documented commands and my existing image node for the editor
  side; if I have no image node, STOP and tell me rather than inventing one.
- Don't block the editor on the upload; insert the node when the URL resolves.

What the agent will do

  • Install @pixelvault-dev/paste (core)
  • Register a DRAG_DROP_PASTE handler that uploads via uploadImage()
  • Insert the returned CDN URL as your Lexical image node
  • No backend changes — uploads go straight to PixelVault with your key

Grab your free key

The one thing the agent can't generate is your publishable key (pv_pub_…) — it's origin-scoped and upload-only, safe to ship in browser code. Create one, add your app's origin, and paste it in.

Get your free key →

Free tier: 200 MB storage, 500 uploads/mo, 1 GB bandwidth. No card.

How this differs from the textarea prompts

The React, Vue, and plain-HTML prompts use our drop-in widget, which attaches to a <textarea>. Lexical renders a contenteditable surface, so the widget can't attach to it — you upload the file yourself with the lower-level uploadImage() helper and insert an image node with the returned CDN URL, exactly like the TipTap and Quill prompts.

Heads-up: Lexical has no built-in image node

Unlike TipTap, Lexical core ships no image node. This prompt inserts into whatever image node your editor already has (e.g. the playground's ImageNode) and tells the agent to stop and flag it if you don't have one — so you won't get code that references a node that doesn't exist.

The PixelVault part, by hand

Everything editor-specific is standard Lexical. The only PixelVault call is one function:

import { uploadImage } from "@pixelvault-dev/paste";

const { url } = await uploadImage(file, {
  publishableKey: "pv_pub_xxxxxxxx",
});
// url → https://img.pixelvault.dev/…  (a permanent CDN URL)
// then insert your image node with { src: url } inside editor.update()

Wire that into Lexical's DRAG_DROP_PASTE command (from @lexical/rich-text), upload each image file, and insert on success. The docs and llms.txt have the full reference.

Why a prompt instead of docs?

Because "add image upload to my Lexical editor" is exactly what you'd hand a coding agent — and it needs to know to use uploadImage() (not a nonexistent widget) and to respect Lexical's image-node requirement. This prompt grounds the PixelVault call and lets the agent handle Lexical's commands. Copy, paste, ship.

FAQ

How do I add image upload to a Lexical editor?

Copy the prompt above into your AI coding agent. Because Lexical is contenteditable (not a textarea), it uses PixelVault's uploadImage() helper inside Lexical's DRAG_DROP_PASTE command, then inserts the returned CDN URL as your image node.

Does Lexical have a built-in image node?

No — Lexical core ships no image node. You need one registered (for example the Lexical playground's ImageNode) before images can be inserted. The prompt tells the agent to stop and flag this if your editor doesn't have one.

Do I need an upload backend for Lexical image uploads?

No. uploadImage() sends the file straight from the browser to PixelVault with an origin-scoped, upload-only publishable key. There's no server route to build.