Custom Tool Example
This page shows how to register a custom "Testimonial" content tool with editable name, quote, and avatar properties and a custom HTML renderer.
src/TestimonialToolEditor.jsx
import React, { useRef, useCallback } from 'react';
import { PexelizeEditor } from '@pexelize/react-editor';
const EDITOR_KEY = 'your-editor-key';
// --- 1. Define the tool ---
const testimonialTool = {
name: 'testimonial',
label: 'Testimonial',
icon: 'https://cdn.example.com/icons/testimonial.svg',
category: 'content',
// Default property values for a new instance
properties: {
authorName: {
label: 'Author Name',
defaultValue: 'Jane Doe',
widget: 'text',
},
quote: {
label: 'Quote',
defaultValue: 'This product changed my workflow completely.',
widget: 'rich_text',
},
avatarUrl: {
label: 'Avatar URL',
defaultValue: 'https://i.pravatar.cc/80',
widget: 'image',
},
starRating: {
label: 'Star Rating (1-5)',
defaultValue: 5,
widget: 'counter',
options: { min: 1, max: 5 },
},
},
// --- 2. HTML renderer ---
renderer: {
render({ values }) {
const stars = '\u2605'.repeat(values.starRating) + '\u2606'.repeat(5 - values.starRating);
return `
<table role="presentation" width="100%" cellpadding="0" cellspacing="0"
style="background:#f9fafb;border-radius:8px;padding:24px;">
<tr>
<td width="64" valign="top">
<img src="${values.avatarUrl}" alt="${values.authorName}"
width="56" height="56"
style="border-radius:50%;object-fit:cover;" />
</td>
<td style="padding-left:16px;">
<p style="margin:0 0 8px;font-style:italic;color:#374151;font-size:15px;">
"${values.quote}"
</p>
<p style="margin:0;font-weight:600;color:#111827;font-size:14px;">
${values.authorName}
</p>
<p style="margin:4px 0 0;color:#f59e0b;font-size:16px;">${stars}</p>
</td>
</tr>
</table>
`;
},
},
};
// --- 3. Use it ---
export default function TestimonialToolEditor() {
const editorRef = useRef(null);
const onReady = useCallback(() => {
editorRef.current?.registerTool(testimonialTool);
console.log('Testimonial tool registered');
}, []);
const exportHtml = useCallback(() => {
editorRef.current?.exportHtml((data) => {
console.log(data.html);
});
}, []);
return (
<div style={{ display: 'flex', flexDirection: 'column', height: '100vh' }}>
<div style={{ padding: 10, display: 'flex', gap: 8 }}>
<button onClick={exportHtml}>Export HTML</button>
</div>
<div style={{ flex: 1 }}>
<PexelizeEditor
ref={editorRef}
editorKey={EDITOR_KEY}
onReady={onReady}
minHeight="100%"
/>
</div>
</div>
);
}
How it works
- Define properties -- each property gets a
widgettype (text,rich_text,image,counter,color,dropdown, etc.) that controls the property editor panel. - Write a renderer --
renderer.render()receives the currentvaluesand returns an HTML string. This HTML is used both inside the editor canvas and in the final export. - Register on ready -- call
registerTool()after the editor firesonReadyso the internal tool registry is initialised.
Property widget reference
| Widget | Value type | Notes |
|---|---|---|
text | string | Single-line input |
rich_text | string | Rich text editor with bold/italic/link |
image | string (URL) | Opens the image picker |
color | string (hex) | Colour picker |
counter | number | Stepper with min/max options |
dropdown | string | Requires options.items array |
toggle | boolean | On/off switch |