Image Uploads

ZynText supports three ways to insert images: toolbar button (file picker), drag-and-drop, and clipboard paste. All three require setting the uploadUrl option.

Enabling Uploads

new ZynText(textarea, {
  uploadUrl: '/api/media/upload',
  deleteUrl: '/api/media',         // Optional: enables server deletion
  csrfToken: 'your-csrf-token'     // Optional: auto-detected from meta tag
});
CSRF Token If csrfToken is not provided, ZynText reads it from <meta name="csrf-token" content="...">.

Upload Methods

  1. Toolbar button: Click the Image button in the toolbar to open a file picker. Multiple files can be selected.
  2. Drag and drop: Drag image files onto the editing area. A "Drop image here" overlay appears. The cursor position at the drop point is used for insertion.
  3. Clipboard paste: Paste images from the clipboard (e.g., screenshots). Automatically intercepted and uploaded.

Upload Request

ZynText sends a POST request with FormData:

POST /api/media/upload
Content-Type: multipart/form-data
X-CSRF-TOKEN: {csrfToken}
Accept: application/json

files[]: (binary image file)
files[]: (binary image file)  // Multiple files supported

Only files with a MIME type starting with image/ are included.

Expected Response

Your server must return JSON in this format:

{
  "success": true,
  "files": [
    {
      "url": "https://example.com/uploads/image-1.jpg",
      "id": 42
    },
    {
      "url": "https://example.com/uploads/image-2.png",
      "id": 43
    }
  ]
}
FieldTypeRequiredDescription
successbooleanYesMust be true for images to be inserted
filesarrayYesArray of uploaded file objects
files[].urlstringYesPublic URL of the uploaded image
files[].idnumber|stringNoMedia ID for server-side deletion

Laravel Server Example

// routes/web.php
Route::post('/admin/media/upload', [MediaController::class, 'upload']);

// MediaController.php
public function upload(Request $request)
{
    $request->validate([
        'files.*' => 'required|image|max:10240',
    ]);

    $uploaded = [];
    foreach ($request->file('files') as $file) {
        $path = $file->store('uploads', 'public');
        $media = Media::create([
            'file_path' => $path,
            'file_name' => $file->getClientOriginalName(),
            'mime_type' => $file->getMimeType(),
            'size' => $file->getSize(),
        ]);

        $uploaded[] = [
            'url' => Storage::url($path),
            'id' => $media->id,
        ];
    }

    return response()->json([
        'success' => true,
        'files' => $uploaded,
    ]);
}

Image Interaction

After an image is inserted, it is auto-selected and the user can:

Server Deletion

When deleteUrl is set and the user chooses "Delete from server":

DELETE /api/media/{mediaId}
X-CSRF-TOKEN: {csrfToken}
Accept: application/json
Content-Type: application/json

{ "url": "https://example.com/uploads/image-1.jpg" }

The mediaId is appended to deleteUrl if the image has a data-media-id attribute. The image is removed from the editor immediately regardless of the server response.

Without Upload (URL Only)

If uploadUrl is not set, the Image button will show a browser prompt asking for a URL. Drag-drop and paste are disabled.

// No upload: Image button prompts for URL
new ZynText(textarea, { toolbar: 'standard' });

Upload Progress

A progress bar appears at the bottom of the editor during uploads. It uses XHR (not fetch) to track upload progress with percentage updates.