Property Control
The cv-property-control addon exposes a single customizable property of a specific element as a standalone UI control mounted outside the customizer. It's designed for focused customization scenarios — like a neon sign builder where users control color, font, size, and text through dedicated controls in the page layout rather than through the sidebar.
Supported Properties
| Property | UI Rendered | Notes |
|---|---|---|
fill | Color palette / picker | Auto-detects mode from the element's colors prop: array → palette, true → picker |
neonColor | Color palette / picker | Same as fill, reads neonColor from CVNeonText elements |
fontFamily | Searchable font grid | Grid of font name tiles rendered in their own font. Uses the configured fonts list |
fontSize | Range slider | Configurable min/max/step via props |
text | Text input | contentEditable div supporting multiline |
Basic Usage
Mount property controls via registerModule() after the customizer is ready:
<cv-customizer id="customizer"></cv-customizer>
<div id="color-control"></div>
<div id="font-control"></div>
<div id="size-control"></div>
<div id="text-control"></div>
const customizer = document.querySelector('#customizer');
customizer.addEventListener('cvReady', async () => {
const register = async (target, attrs) => {
await customizer.registerModule('property-control', target);
const el = document.querySelector(target)?.querySelector('cv-property-control');
if (el) {
for (const [k, v] of Object.entries(attrs)) {
el.setAttribute(k, v);
}
}
};
await register('#color-control', { target: 'Neon Text', property: 'neonColor', label: 'Color' });
await register('#font-control', { target: 'Neon Text', property: 'fontFamily', label: 'Font' });
await register('#size-control', { target: 'Neon Text', property: 'fontSize', label: 'Size', min: '20', max: '120' });
await register('#text-control', { target: 'Neon Text', property: 'text', label: 'Your Text' });
});
The target attribute matches the element by its title property in the product data.
Props Reference
| Property | Type | Default | Description |
|---|---|---|---|
chamevo | ChamevoJS | (auto from store) | ChamevoJS instance. Falls back to uiState.chamevo if not set. |
target | string | (required) | Element title to control. Must match an element's title in the loaded product. |
property | string | (required) | Property to control: fill, neonColor, fontFamily, fontSize, or text. |
label | string | (auto-derived) | Display label above the control. Auto-derived from property name if omitted. |
options | string | string[] | — | Override available colors (for fill/neonColor) or font names (for fontFamily). Accepts JSON string, comma-separated string, or array. |
min | number | 10 | Minimum value for fontSize slider. |
max | number | 200 | Maximum value for fontSize slider. |
step | number | 1 | Step increment for fontSize slider. |
columns | number | (auto-fill) | Fixed number of columns for the font grid. Default uses auto-fill with minmax(100px, 1fr). |
Property-Specific Behavior
Color (fill / neonColor)
Renders a cv-color-panel component. The color mode is auto-detected from the target element:
- Palette mode — element has a
colorsarray with 2+ entries → shows swatches - Picker mode — element has
colors: trueor a single-color array → shows free picker
Override the available colors via the options prop:
<cv-property-control
target="Neon Text"
property="neonColor"
options='["#ff6ec7", "#00ffff", "#ff4444", "#39ff14", "#ffffff"]'
></cv-property-control>
Font Family (fontFamily)
Renders a searchable grid of font tiles. Each tile displays the font name rendered in its own font face. The font list comes from:
- The
optionsprop (if set) — comma-separated or JSON array of font names - The
fontsoption configured on the customizer
When switching fonts, unsupported variants (bold/italic) are automatically stripped.
Font Size (fontSize)
Renders a cv-slider component with configurable min, max, and step. Live preview updates the element during drag; history is committed on release.
Text (text)
Renders a contentEditable div supporting multiline input. For CVNeonText elements, text is routed through setNeonProperty() which propagates to all internal text layers.
History Integration
All property changes integrate with undo/redo:
- Slider drag: State is captured before the drag starts, committed on release
- Color input: State captured on first interaction, committed on palette/picker release
- Font select: Single history entry per font change
- Text input: State captured on first keystroke, committed on blur
Reactivity
The control automatically refreshes when:
- A new product is loaded (
productCreateevent) - The element's fill changes externally (
elementFillChangeevent) - Undo/redo is triggered (
historyUndo/historyRedoevents) - An element is modified on canvas (
object:modifiedevent) - The active view changes
CSS Custom Properties
| Variable | Default | Description |
|---|---|---|
--cv-pc-gap | 8px | Gap between the label and the control |
--cv-pc-font-grid-cols | repeat(auto-fill, minmax(100px, 1fr)) | Font grid column template |
Example: Neon Sign Builder
A complete neon sign customizer with external property controls and no sidebar modules:
import { createCustomizer } from '@chamevo/customizer';
const customizer = createCustomizer('#container', {
mainBarModules: [],
actions: [],
bottomActions: [],
toolbar: { placement: 'hidden' },
fonts: [
{ name: 'Neonderthaw', url: 'google' },
{ name: 'Tilt Neon', url: 'google' },
{ name: 'Pacifico', url: 'google' },
{ name: 'Great Vibes', url: 'google' },
],
});
customizer.addEventListener('cvReady', async () => {
await customizer.loadProduct(neonProduct);
// Mount controls into your page layout
const mount = async (selector, attrs) => {
await customizer.registerModule('property-control', selector);
const el = document.querySelector(selector)?.querySelector('cv-property-control');
if (el) Object.entries(attrs).forEach(([k, v]) => el.setAttribute(k, v));
};
await mount('#color', { target: 'Neon Text', property: 'neonColor', label: 'Color' });
await mount('#font', { target: 'Neon Text', property: 'fontFamily', label: 'Font' });
await mount('#text', { target: 'Neon Text', property: 'text', label: 'Your Text' });
});
Next Steps
- Custom & External Modules —
registerModule()API and external mounting - Fonts — Font configuration and loading
- Theming — CSS custom property theming system
- Elements — Element types including neon text