Skip to main content

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:

  1. Select the new visualization in the feature settings under "Display"
  2. The key of the visualization is saved in variable.settings.template
  3. 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.