Skip to main content

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

PropertyUI RenderedNotes
fillColor palette / pickerAuto-detects mode from the element's colors prop: array → palette, true → picker
neonColorColor palette / pickerSame as fill, reads neonColor from CVNeonText elements
fontFamilySearchable font gridGrid of font name tiles rendered in their own font. Uses the configured fonts list
fontSizeRange sliderConfigurable min/max/step via props
textText inputcontentEditable 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

PropertyTypeDefaultDescription
chamevoChamevoJS(auto from store)ChamevoJS instance. Falls back to uiState.chamevo if not set.
targetstring(required)Element title to control. Must match an element's title in the loaded product.
propertystring(required)Property to control: fill, neonColor, fontFamily, fontSize, or text.
labelstring(auto-derived)Display label above the control. Auto-derived from property name if omitted.
optionsstring | string[]Override available colors (for fill/neonColor) or font names (for fontFamily). Accepts JSON string, comma-separated string, or array.
minnumber10Minimum value for fontSize slider.
maxnumber200Maximum value for fontSize slider.
stepnumber1Step increment for fontSize slider.
columnsnumber(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 colors array with 2+ entries → shows swatches
  • Picker mode — element has colors: true or 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:

  1. The options prop (if set) — comma-separated or JSON array of font names
  2. The fonts option 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 (productCreate event)
  • The element's fill changes externally (elementFillChange event)
  • Undo/redo is triggered (historyUndo / historyRedo events)
  • An element is modified on canvas (object:modified event)
  • The active view changes

CSS Custom Properties

VariableDefaultDescription
--cv-pc-gap8pxGap between the label and the control
--cv-pc-font-grid-colsrepeat(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