defineComponent API Reference
This document details the exact API signatures, options, and types for Coralite's core defineComponent plugin.
For a conceptual guide on how to use dynamic components, see the Components Guide.
Signature #
function defineComponent(options: DefineComponentOptions): PluginDefinition
Options Object (DefineComponentOptions) #
The defineComponent function accepts a single configuration object with the following isolated blocks. Note: All components MUST have a hyphen in their name (e.g., <my-component>).
| Property | Type | Description |
|---|---|---|
attributes |
Record<string, AttributeSchema> |
Defines and coerces HTML attributes into JS primitives. |
server |
(context: CoraliteServerContext) => Promise<Record<string, any>> |
A server-side async function for fetching initial state. Stripped from the client bundle. Formerly known as data. |
getters |
Record<string, (state: ReadonlyState) => any> |
Pure functions for derived state. Receives a read-only state proxy. |
style |
Record<string, ((state: ReadonlyState) => string | number | null | undefined | false) | string | number> |
Declarative, reactive CSS properties and CSS Custom Properties (--*). |
client |
(context: CoraliteScriptContext) => void |
The client-side controller. Receives a read/write state proxy. Formerly known as script. |
slots |
Record<string, CoraliteModuleSlotFunction> |
Functions for processing and transforming slot content. |
1. attributes #
The attributes block defines the inputs your component accepts from HTML. Coralite automatically coerces, transforms, and validates these values through a robust attribute schema engine.
attributes: {
// Type shorthand syntax
expanded: Boolean,
// Array shorthand syntax (implicit String type & values check)
variant: ['primary', 'secondary', 'danger'],
// Verbose schema definition with transform and validate pipeline
theme: { type: String, default: 'light', values: ['light', 'dark', 'system'] },
maxItems: { type: Number, default: 10, validate: (val) => val > 0 || 'maxItems must be positive' },
apiKey: { type: String, required: true },
slug: {
type: String,
transform: (val) => val.toLowerCase().trim(),
validate: (val) => val.length >= 3 || 'Slug must be at least 3 characters'
}
}
Attribute Schema Configuration #
| Property | Type | Description |
|---|---|---|
type |
Boolean | Number | String |
Primitive constructor used for coercion. Required in verbose schema. |
default |
any |
Default value if attribute is absent. Cannot be combined with required: true (Definition Mutex). |
values |
Array<any> |
Allowed primitive value set. In array shorthand (e.g., status: ['a', 'b']), `type` defaults to `String`. |
required |
boolean |
When true, marks attribute as mandatory. Missing attributes gracefully record an error in state.errors and error_* tokens during runtime. Cannot be combined with default. |
transform |
(val: any) => any |
Synchronous transformation function run after coercion. Must not return a Promise. |
validate |
(val: any) => boolean | string | void |
Synchronous predicate. Returns true/void on success, false for default error, or string for custom error message. |
The 6-Step Attribute Execution Lifecycle Pipeline & Graceful Error Handling #
Attributes execute sequentially through a strict 6-step lifecycle pipeline during component initialization and state changes. When validation fails (e.g., missing required attribute, values enum mismatch, or validate predicate failure), Coralite records the error message gracefully in state.errors and flat error_* tokens without halting SSR or crashing client scripts:
- 1.
requiredCheck: Asserts attribute presence ifrequired: trueis configured. Records"Attribute \"on omission.\" is required." - 2. Type
coerce: Coerces raw attribute string into specified primitive constructor (Boolean,Number, orString). - 3.
transform: Runs custom synchronoustransform(val)function to format or sanitize value. Thrown errors are recorded instate.errorswhile retaining the attempted value. - 4.
valuesCheck: Validates that value exists in allowedvalues: [...]enumeration array. Records formatted expected values error on mismatch. - 5.
validate: Invokes custom synchronousvalidate(val)predicate/function. Returningfalsesets default error message; returning a string records custom message; throwing records error message. - 6. State Application: Applies the validated value or retains attempted input in
state[key]and updates reactivestate.errorsand flaterror_*template tokens.
Graceful Attribute Validation (state.errors & error_* Tokens) #
Coralite provides two zero-overhead mechanisms to display and handle attribute validation feedback:
- JS Access (
state.errors): A reactive dictionary mapping camelCase attribute names to error string messages (e.g.state.errors.age). Implemented as a nested reactiveProxythat automatically tracks getter and observer dependencies on read, symmetrically updates both camelCase and kebab-case flaterror_*tokens on mutation/deletion, and schedules reactive DOM re-renders upon property mutation, deletion, or whole-object assignment (state.errors = { ... }). When all attributes are valid,Object.keys(state.errors).length === 0. - Flat Template Tokens (
{{ error_fieldName }}): Automatic flat template tokens populated on state in both camelCase and kebab-case aliases (e.g.{{ error_userAge }}and{{ error_user-age }}). Default to""(empty string) when valid. - Client Context (
errors): Provided directly in client controller signatures:client: ({ state, errors, ... }) => ....
Coralite maps declared attribute names from camelCase (e.g., isChecked) to their kebab-case equivalent in HTML (e.g., is-checked) and coerces them into JavaScript primitives. Changes to HTML attributes via setAttribute automatically update their values in the component state.
Coercion Logic #
The coercion rules for the supported primitive constructors are detailed below:
-
Boolean: Coerced using
value === '' ? true : (value !== 'false' && value !== null)on both server and client. Empty attributes likedisabledevaluate totrue. - Number: Evaluated using
Number(value). Strings that are not valid numbers resolve toNaN. - String: Evaluated using
String(value).
Coercion Matrix Reference #
| Input HTML Attribute Value | Boolean Coercion | Number Coercion | String Coercion |
|---|---|---|---|
"true" |
true |
NaN |
"true" |
"false" |
false |
NaN |
"false" |
"42" |
true |
42 |
"42" |
"0" |
true |
0 |
"0" |
"" (empty attribute) |
true |
0 |
"" |
null (absent) |
false (or default) |
null (or default) |
null (or default) |
"hello" |
true |
NaN |
"hello" |
Native HTML Boolean Attributes & WAI-ARIA (aria-*) Auto-Removal #
When single reactive state tokens are bound to element attributes within templates, Coralite applies intelligent toggling and auto-removal rules depending on the attribute type:
-
43 Standard Native HTML Boolean Attributes (Presence Toggling):
When bound to a boolean attribute (such as
disabled="{{ isDisabled }}",hidden="{{ isHidden }}",required="{{ isReq }}",allowpaymentrequest="{{ pay }}"), if the value resolves to falsy (false,"false",null,"null",undefined,"undefined","",0,"0"), the attribute is completely removed from the element. When truthy, it is rendered as an empty string presence attribute (e.g.disabled="").
Supported 43 Boolean Attributes:allowfullscreen,allowpaymentrequest,async,autofocus,autoplay,checked,compact,controls,credentialless,declare,default,defer,disabled,disablepictureinpicture,disableremoteplayback,formnovalidate,hidden,inert,ismap,itemscope,loop,multiple,muted,nohref,nomodule,noresize,noshade,novalidate,nowrap,open,playsinline,readonly,required,reversed,scoped,seamless,selected,shadowrootclonable,shadowrootdelegatesfocus,shadowrootserializable,truespeed,typemustmatch, andwebkitdirectory. -
WAI-ARIA Attributes (
aria-*Auto-Removal): When anaria-*attribute (e.g.aria-hidden="{{ isHidden }}",aria-expanded="{{ expanded }}",aria-label="{{ label }}",aria-valuenow="{{ progress }}") is bound with a single template token:- If the value evaluates to falsy (
false,"false",null,"null",undefined,"undefined",""), the attribute is completely removed from the element. - Numeric 0 / "0" Preservation: Numeric
0and"0"are valid ARIA values (e.g.,aria-valuenow="0") and do NOT trigger removal. They resolve to"0". - If truthy (or
0), the attribute is set to its evaluated string representation (e.g.,aria-hidden="true",aria-label="Search").
- If the value evaluates to falsy (
-
Standard Custom Attributes: Standard custom or unreserved attributes (e.g.
is-active="{{ isActive }}") are evaluated as string values (e.g.,is-active="false").
To prevent complex JSON-in-HTML parsing errors and ensure performance, attributes only support String, Number, and Boolean. Use the server block or slots for complex data structures.
Note: If you use the no-hydration attribute, the host tag is completely removed (spliced) and replaced by its contents. Learn more in the SSR Guide.
2. server (Server-Side) #
The server block is used for heavy-lifting, such as database queries or API calls. This code runs only on the server during the build process and is completely removed from the JavaScript sent to the browser. Formerly known as data.
async server(context) {
const users = await db.users.findMany();
return { users };
}
Note: In testing mode, you can override this block for specific components to provide deterministic mock data.
3. getters (Derived State) #
Getters are pure functions used to calculate derived data. They are reactive; if an attribute or a data value changes, the getter automatically re-calculates.
getters: {
// state is a Read-Only Proxy here
visibleUsers: (state) => state.users.slice(0, state.maxItems)
}
4. style (Declarative Reactive CSS) #
The style block defines declarative, reactive inline CSS properties and CSS Custom Properties (--*) on the custom element host tag.
style: {
// CSS Custom Property (preserved with -- prefix)
'--accent-color': (state) => state.theme === 'dark' ? '#38bdf8' : '#0284c7',
// Standard CSS property (automatically camelCase -> kebab-case)
backgroundColor: (state) => state.isActive ? '#e0f2fe' : null,
fontSize: (state) => `${state.size}px`,
// Static values
cursor: 'pointer'
}
Style Property Normalization & Removal Semantics #
- Property Name Normalization: Standard camelCase properties (e.g.,
backgroundColor) are automatically converted to kebab-case (e.g.,background-color). Custom property names starting with--are preserved as-is. - Removal Triggers: Returning
null,undefined,false, or''(empty string) removes the property from the host element's inline style (`this.style.removeProperty()` on client, omitted in SSR). - Zero Value Preservation: Returning the numeric value
0(zero) is strictly preserved as valid CSS (e.g.,opacity: 0). - Synchronous Function Enforcement: Style getter functions must be strictly synchronous. Returning a
Promisethrows aCoraliteError.
5. client (Client-Side) #
The client block is the controller for your component in the browser. This is where you add event listeners, mutate state, and dispatch custom events. Formerly known as script.
client: ({ state, signal, refs, observe, emit }) => {
// Access unique DOM elements via the 'refs' utility
const btn = refs('loadMoreBtn');
// Register an observer to react to state changes
observe('maxItems', (newVal, oldVal) => {
console.log(`maxItems updated from ${oldVal} to ${newVal}`);
});
btn.addEventListener('click', () => {
// Imperative mutation triggers DOM updates
state.maxItems += 10;
// Dispatch custom DOM event to parent components
emit('items-expanded', { count: state.maxItems });
}, { signal }); // Use the provided 'signal' for auto-cleanup
}
CoraliteScriptContext #
| Property | Type | Description |
|---|---|---|
state |
Proxy |
The Read/Write reactive state (Attributes + Data + Getters). |
signal |
AbortSignal |
Used for cleaning up event listeners and aborting fetches on unmount. |
root |
HTMLElement |
The DOM element instance of the component. |
instanceId |
string |
A unique identifier for this specific instance. |
refs |
(id: string) => HTMLElement | null |
A utility to query unique elements by their ref name. |
observe |
(key: string, callback: (newVal: any, oldVal: any) => void) => void |
Registers a callback to execute explicit side-effects on state changes. Automatically cleaned up when the component is disconnected. |
emit |
(name: string, detail?: any, options?: CustomEventInit) => boolean |
Helper function to dispatch custom DOM events from the host element. Defaults to { bubbles: true, composed: true, cancelable: false }. Returns true if event was not cancelled via preventDefault(). |
6. slots #
Allows you to intercept and transform content passed into your component's slots.
type CoraliteSlotContext<state = any> = {
state: State; // reactive proxy (client) / plain merged state (SSR)
observe: (prop: string, cb: (newVal: any, oldVal?: any) => any) => () => void; // ALWAYS returns a disposer
signal: AbortSignal;
root: HTMLElement | null; // element on client, null during SSR build
refs: (name: string) => HTMLElement | null; // no-op returning null on SSR
instanceId: string;
} & Record<string, any>
type SlotTransformer<state = any> = (
nodes: Node[],
context: CoraliteSlotContext<state>
) => Node[] | Node | string | null | Promise<node[] | node string null>
</node[]></state></state></string,></state>
The Void = Bypass Paradigm #
To ensure high performance and prevent unnecessary re-rendering during client-side hydration, Coralite uses a "Void = Bypass" approach for slot transformations:
undefined(Bypass): Signals the framework to skip processing and preserve the current content. On the server, it preserves the original AST nodes; on the client, it preserves the existing DOM nodes. Use this in the browser to prevent flushing SSR-rendered content.null,"", or[](Clear): Explicitly instructs the framework to remove all content from the slot.
slots: {
default: (nodes, state) => {
// Bypass hydration in the browser to preserve SSR content
if (typeof window !== 'undefined') return undefined;
// Otherwise, perform complex transformation on the server
return nodes.map(n => transform(n));
}
}