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
});
csrfToken is not provided, ZynText reads it from <meta name="csrf-token" content="...">.
Upload Methods
- Toolbar button: Click the Image button in the toolbar to open a file picker. Multiple files can be selected.
- 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.
- 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
}
]
}
| Field | Type | Required | Description |
|---|---|---|---|
success | boolean | Yes | Must be true for images to be inserted |
files | array | Yes | Array of uploaded file objects |
files[].url | string | Yes | Public URL of the uploaded image |
files[].id | number|string | No | Media 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:
- Resize: Drag any of 8 handles (corners + edges). Proportional resize is enforced.
- Align: Inline, Float Left, Float Right, or Center (uses
<figure>wrapper with inline styles). - Shrink / Grow: Resize by ±10% steps.
- Restore Size: Remove explicit dimensions, reverting to the image's natural size.
- Edit Margin: Set top, right, bottom, left margins in pixels.
- Edit Alt Text: Set the image's
altattribute. - Delete: Remove from the editor only, or also delete from the server.
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.