The .kcomponent file format is a YAML-based format for defining custom components that can be imported into Karbonized. It contains a manifest with metadata and the component's HTML, CSS, and JavaScript code.
A .kcomponent file is a YAML file with the following structure. Only
manifest.name and html are required; css and js can be omitted.
manifest:
name: "Component Name"
author: "Author Name"
description: "Component description"
version: "1.0.0"
category: "Category Name"
tags:
- "tag1"
- "tag2"
html: |
<div class="component">
<!-- HTML content -->
</div>
css: |
:root {
/* CSS variables with type annotations */
/* @type:color */
--primary-color: #3b82f6;
/* @type:number min:0 max:50 step:1 unit:px */
--spacing: 16px;
}
js: |
// JavaScript code
// @var variable:type = "value"
// @action:Action Label
// action code| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | The name of the component (max. 80 chars) |
author |
string | No | The author of the component (max. 80 chars) |
description |
string | No | A brief description of the component (max. 500 chars) |
version |
string | No | Version following semantic versioning (e.g., "1.0.0") |
category |
string | No | Category for organizing components (e.g., "UI Components", "Forms") |
tags |
array of strings | No | Tags for searching and filtering (max. 12, comma separated text is also accepted) |
width |
number | No | Preferred block width in px when added to the canvas (16–4096) |
height |
number | No | Preferred block height in px when added to the canvas (16–4096) |
thumbnail |
string | No | Preview image shown in the library: an https:// URL or an inline data:image/…;base64, value |
name and author together identify a component: importing a file with the
same pair updates the existing entry instead of creating a duplicate.
The html field contains the HTML markup for the component. This HTML will be rendered within a Shadow DOM to prevent style conflicts with other components.
Example:
html: |
<div class="custom-button">
<button class="btn">Click Me</button>
</div>The css field contains the CSS styles for the component. Karbonized supports a special system of CSS variables with type annotations that automatically generate UI controls in the properties panel.
/* @type:color */
--primary-color: #3b82f6;Generates a color picker in the properties panel.
/* @type:number min:0 max:50 step:1 unit:px */
--border-radius: 8px;Generates a slider control with the specified range and unit.
Parameters:
min: Minimum valuemax: Maximum valuestep: Increment stepunit: Unit to display (e.g., "px", "em", "%")
/* @type:shadow */
--box-shadow: 0px 2px 4px rgba(0,0,0,0.2);Generates a shadow editor in the properties panel.
/* @type:boolean */
--show-shadow: true;Generates a toggle switch in the properties panel.
/* @type:icon */
--feature-icon: FaRocket;Generates an icon picker in the properties panel with the built-in Font Awesome
icons (FaRocket) and the icons of the installed icon packs (acme:bolt). When the block renders, the
name becomes the image of the icon, meant for a mask. Draw it with the built-in
.k-icon helper, which takes the text color and is 1em square:
<span class="k-icon" style="--k-icon: var(--feature-icon)"></span>Font Awesome icons are always there. An icon from a pack the user has not installed draws nothing, so a shared component should default to a Font Awesome icon or say which pack it needs.
A .kcomponent with manifest.type: icon-pack holds icons instead of HTML:
an icons map of names to SVG markup, plus a prefix that names the pack's
icons (acme:bolt). Importing one adds its icons to the Icon block, to
@type:icon variables and to the component library. See
icon-packs.md for the full format, the SVG rules and the
yarn icon-pack script that builds a pack from a folder of SVG files.
Name a Google font in font-family and the app loads it for the block (a
@import of Google Fonts is also understood). Fonts have to be loaded by the
page: a shadow root cannot load them by itself.
css: |
:root {
/* @type:color */
--btn-color: #3b82f6;
/* @type:color */
--btn-text: #ffffff;
/* @type:number min:0 max:50 step:1 unit:px */
--btn-radius: 8px;
/* @type:number min:8 max:32 step:1 unit:px */
--btn-padding: 12px;
/* @type:shadow */
--btn-shadow: 0px 2px 4px rgba(0,0,0,0.2);
/* @type:boolean */
--show-shadow: true;
}
.btn {
background: var(--btn-color);
color: var(--btn-text);
padding: var(--btn-padding) 24px;
border-radius: var(--btn-radius);
box-shadow: var(--btn-shadow);
}The js field contains JavaScript code that can interact with the component and the Karbonized environment.
You can define JavaScript variables that will appear in the properties panel:
// @var message:string = "Hello!"This creates a text input in the properties panel for the message variable.
You can define custom actions that can be triggered from the component or the properties panel:
// @action:Show Alert
alert(message);This creates a button labeled "Show Alert" in the properties panel that executes the code.
The JavaScript code has access to the htmlBlockAPI object with the following methods:
log(message): Log a message to the dev consolewarn(message): Log a warningerror(message): Log an errorrefresh(): Force refresh the Shadow DOMregisterAction(label, callback): Register a custom actiongetVariable(name): Get the value of a CSS variablesetVariable(name, value): Set the value of a CSS variable
js: |
// @var message:string = "Hello from custom component!"
// @action:Show Alert
alert(message);
// @action:Change Color
const colors = ['#3b82f6', '#ef4444', '#10b981', '#f59e0b'];
const randomColor = colors[Math.floor(Math.random() * colors.length)];
document.documentElement.style.setProperty('--btn-color', randomColor);manifest:
name: "Custom Button"
author: "Your Name"
description: "A customizable button component"
version: "1.0.0"
category: "UI Components"
tags:
- "button"
- "interactive"
html: |
<div class="custom-button">
<button class="btn">Click Me</button>
</div>
css: |
:root {
/* @type:color */
--btn-color: #3b82f6;
/* @type:color */
--btn-text: #ffffff;
/* @type:number min:0 max:50 step:1 unit:px */
--btn-radius: 8px;
/* @type:number min:8 max:32 step:1 unit:px */
--btn-padding: 12px;
/* @type:number min:12 max:24 step:1 unit:px */
--btn-font-size: 16px;
/* @type:shadow */
--btn-shadow: 0px 2px 4px rgba(0,0,0,0.2);
/* @type:boolean */
--show-shadow: true;
}
.custom-button {
padding: 20px;
}
.btn {
background: var(--btn-color);
color: var(--btn-text);
border: none;
padding: var(--btn-padding) 24px;
border-radius: var(--btn-radius);
cursor: pointer;
font-size: var(--btn-font-size);
transition: opacity 0.2s;
box-shadow: var(--btn-shadow);
}
.btn:hover {
opacity: 0.9;
}
js: |
// @var message:string = "Hello from custom component!"
// @action:Show Alert
alert(message);
// @action:Change Color
const colors = ['#3b82f6', '#ef4444', '#10b981', '#f59e0b', '#8b5cf6'];
const randomColor = colors[Math.floor(Math.random() * colors.length)];
document.documentElement.style.setProperty('--btn-color', randomColor);
// @action:Toggle Shadow
const currentShadow = getComputedStyle(document.documentElement)
.getPropertyValue('--show-shadow')
.trim();
const btn = document.querySelector('.btn');
if (currentShadow === 'true') {
btn.classList.add('no-shadow');
document.documentElement.style.setProperty('--show-shadow', 'false');
} else {
btn.classList.remove('no-shadow');
document.documentElement.style.setProperty('--show-shadow', 'true');
}The importer separates hard errors (the file is rejected) from warnings (the file is imported, but a field was dropped or normalized).
Errors:
- The YAML must be valid; syntax errors report the offending line
- The
manifestfield is required and must be an object manifest.nameis requiredhtmlis required and cannot be emptyhtml,cssandjsmust be text, and each section must stay under 512 KB- The whole file must stay under 1 MB
Warnings:
cssorjsmissing: the component is imported without styles or actions- Unknown fields, at the root or inside the manifest, are ignored
- Text fields longer than their limit are truncated
- Duplicate tags are removed, and only the first 12 are kept
width/heightoutside 16–4096 px are ignored- A
thumbnailthat is not anhttps://URL or an inline base64 image is ignored - A
versionthat does not look like1.2.3is kept but flagged
| Limit | Value |
|---|---|
| Maximum file size | 1 MB |
Maximum size per html/css/js section |
512 KB |
| Maximum components in the library | 200 |
- Use Shadow DOM-safe CSS: Since components render in Shadow DOM, avoid relying on global styles
- Use CSS Variables: Leverage the variable system for easy customization
- Provide meaningful descriptions: Help users understand what your component does
- Use appropriate tags: Make your components discoverable through search
- Version your components: Use semantic versioning to track changes
- Test actions: Ensure all custom actions work correctly
- Provide sensible defaults: Set reasonable default values for CSS variables