Input components
Input components allow you to create your own visualizations for variables (characteristics). You can register custom input widgets for each variable type, which administrators can then select in the backend.
Basic structure
Input components are registered in the ui.inputs object grouped by variable type:
// In Plugin.tsx
export default {
// ...
ui: {
inputs: {
number: [ /* Visualisierungen für Zahlen */ ],
color: [ /* Visualisierungen für Farben */ ],
list: [ /* Visualisierungen für Listen */ ],
// weitere Typen...
}
}
}
A single input component registration:
__PROTECTED_0__
__PROTECTED_1__
const sliderVisualisation: VariableVisualisation = {
key: "vendor.slider",
label: "Slider",
description: "Numerische Eingabe als Schieberegler",
component: MySliderInput
};
VariableVisualization
Each input component is a VariableVisualisation with:
- key: Unique key (e.g. "vendor.slider")
- label: Display name in the Admin UI
- description: Description (string or localized string)
- component: The React component for the input
Variable types
The following variable types can be extended:
__PROTECTED_2__
// Verfügbare Typen:
VariableType.List // "list" - Auswahllisten
VariableType.Color // "color" - Farbauswahl
VariableType.Number // "number" - Numerische Eingabe
VariableType.Text // "text" - Texteingabe
VariableType.Boolean // "boolean" - Ja/Nein
VariableType.Image // "image" - Bildupload
VariableType.Upload // "upload" - Dateiupload
VariableType.Components // "components" - Produktkomponenten
VariableType.Information // "information" - Info-Anzeige
Component Props
Each input component receives K3VariableComponentProps:
interface K3VariableComponentProps {
/** Die Variable, für die diese Komponente gerendert wird */
variable: {
id: string | number;
label: string;
type: VariableTypes;
settings?: {
template?: string; // Key der gewählten Visualisierung
templateOptions?: {
min?: number;
max?: number;
digits?: number;
[key: string]: unknown;
};
};
};
/** Aktuelle Auswahl */
selection?: {
id: string | number;
data?: {
inputValue?: number; // Für number-Variablen
[key: string]: unknown;
};
};
/** Verfügbare Werte */
values?: Array<{
id: string | number;
label: string;
value?: string | boolean | null; // hex color, boolean, etc.
}>;
/** Callback zum Setzen der Auswahl */
onChange: (
valueId: string | number,
metadata?: { inputValue?: number }
) => void;
/** Wenn true, ist die Variable gesperrt */
disabled?: boolean;
}
Example: Slider for Number
__PROTECTED_3__
export const MySliderInput: React.FC<K3VariableComponentProps> = ({
variable,
selection,
values,
onChange,
disabled
}) => {
// Für number-Variablen gibt es typischerweise einen einzigen Wert
const value = values?.[0];
const currentValue = selection?.data?.inputValue ?? 0;
const min = variable.settings?.templateOptions?.min ?? 0;
const max = variable.settings?.templateOptions?.max ?? 100;
const step = 1 / Math.pow(10, variable.settings?.templateOptions?.digits ?? 0);
const handleChange = (newValue: number) => {
if (value?.id) {
onChange(value.id, { inputValue: newValue });
}
};
return (
<div className="slider-input">
<label>{variable.label}</label>
<input
type="range"
min={min}
max={max}
step={step}
value={currentValue}
onChange={(e) => handleChange(parseFloat(e.target.value))}
disabled={disabled}
/>
<span className="slider-value">{currentValue}</span>
</div>
);
};
Example: Custom Color Picker
__PROTECTED_4__
__PROTECTED_5__
export const MyColorPicker: React.FC<K3VariableComponentProps> = ({
variable,
selection,
values,
onChange,
disabled
}) => {
const [hexInput, setHexInput] = useState("");
return (
<div className="color-picker">
<label>{variable.label}</label>
{/* Farb-Swatches */}
<div className="color-swatches">
{values?.map((val) => (
<button
key={val.id}
className={`swatch ${selection?.id === val.id ? "active" : ""}`}
style={{ backgroundColor: val.value as string }}
onClick={() => onChange(val.id)}
disabled={disabled}
>
{val.label}
</button>
))}
</div>
{/* HEX-Eingabe */}
<div className="hex-input">
<label>HEX:</label>
<input
type="text"
value={hexInput}
onChange={(e) => setHexInput(e.target.value)}
placeholder="#FF0000"
disabled={disabled}
/>
</div>
</div>
);
};
Example: Custom list with images
__PROTECTED_6__
export const MyImageList: React.FC<K3VariableComponentProps> = ({
variable,
selection,
values,
onChange,
disabled
}) => {
return (
<div className="image-list">
<h3>{variable.label}</h3>
<div className="image-grid">
{values?.map((val) => (
<div
key={val.id}
className={`image-card ${selection?.id === val.id ? "selected" : ""}`}
onClick={() => !disabled && onChange(val.id)}
>
<img src={val.thumbnail} alt={val.label} />
<span className="image-label">{val.label}</span>
</div>
))}
</div>
</div>
);
};
onChange for different types
List, Color, Boolean, Image, Upload, Components
Simply pass the value ID:
onChange(valueId);
Number
Transfer value ID with inputValue metadata:
onChange(valueId, { inputValue: numericValue });
Text
Transfer value ID with inputText metadata (see K3 internals):
onChange(valueId, { inputText: textValue });
Use template options
Admins can configure template options in the backend. Access them in the component:
const options = variable.settings?.templateOptions;
const showLabels = options?.showLabels ?? true;
const columns = options?.columns ?? 3;
const customValue = options?.myCustomOption;
Localized descriptions
__PROTECTED_7__
{
key: "vendor.slider",
label: "Slider",
description: {
de: "Numerische Eingabe als Schieberegler",
en: "Numeric input as slider",
fr: "Entrée numérique comme curseur",
nl: "Numerieke invoer als schuifregelaar"
} as LocalizedString,
component: MySliderInput
}
All types in one plugin
__PROTECTED_8__
__PROTECTED_9__
// Verschiedene Input-Komponenten definieren
__PROTECTED_10__
__PROTECTED_11__
__PROTECTED_12__
__PROTECTED_13__
__PROTECTED_14__
__PROTECTED_15__
// Im Plugin registrieren:
export default {
// ...
ui: {
inputs: {
list: [
{
key: "vendor.imageList",
label: "Bild-Liste",
description: "Listenauswahl mit Bildern",
component: MyImageList
}
],
color: [
{
key: "vendor.colorPicker",
label: "Erweiterter Farbwähler",
description: "Farbwähler mit HEX-Eingabe",
component: MyColorPicker
}
],
number: [
{
key: "vendor.slider",
label: "Slider",
description: "Schieberegler für Zahlen",
component: MySliderInput
},
{
key: "vendor.spinButton",
label: "Spin-Button",
description: "Plus/Minus Buttons",
component: MySpinButton
}
],
boolean: [
{
key: "vendor.toggle",
label: "Toggle Switch",
description: "iOS-Style Toggle",
component: MyToggle
}
],
text: [
{
key: "vendor.richText",
label: "Rich Text Editor",
description: "Formatierte Texteingabe",
component: MyRichText
}
]
}
}
};
Use in the backend
After the plugin installation, administrators can:
- Select the new visualization in the feature settings under "Display"
- The key of the visualization is saved in
variable.settings.template - Optionally configure template options
Best practices
1. respect disabled state
If disabled={true}, the component should not allow any interaction:
<input disabled={disabled} />
<button onClick={handleClick} disabled={disabled} />
2. error handling
Check for missing or invalid data:
if (!values || values.length === 0) {
return <div>Keine Werte verfügbar</div>;
}
3. accessibility
Use semantic HTML and ARIA attributes:
<input
type="range"
aria-label={variable.label}
aria-valuemin={min}
aria-valuemax={max}
aria-valuenow={currentValue}
/>
4. performance
Memoize expensive calculations:
const sortedValues = useMemo(
() => values?.sort((a, b) => a.label.localeCompare(b.label)),
[values]
);
5. use TypeScript
Use the types provided:
__PROTECTED_16__
K3VariableComponentProps,
VariableVisualisation
} from "k3-plugin-api";
export const MyInput: React.FC<K3VariableComponentProps> = (props) => {
// TypeScript kennt jetzt alle Props
};
Debugging
Log props during development:
export const MyInput: React.FC<K3VariableComponentProps> = (props) => {
console.log("Variable:", props.variable);
console.log("Selection:", props.selection);
console.log("Values:", props.values);
return <div>...</div>;
};
Complete example
See the k3-sample-plugin Repository for complete, working examples of all input types.