<!-- Markdown twin of https://pixelvault.dev/prompts/lexical-image-paste -->

Copy-paste prompt · Lexical

# 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 Code``Cursor``Windsurf``Copilot`

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 Copy prompt

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 →](/signup)

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

## How this differs from the textarea prompts

The [React](/prompts/react-image-paste), [Vue](/prompts/vue-image-paste), and [plain-HTML](/prompts/html-image-paste) 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](/prompts/tiptap-image-paste) and [Quill](/prompts/quill-image-paste) 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](/docs#paste) and [`llms.txt`](/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.
