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, (context: CoraliteGetterContext) => any> |
Pure functions for derived state. Receives single context object parameter { state, root, refs, signal }. |
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. |
formAssociated |
boolean |
Opt-in flag enabling Form-Associated Custom Elements (FACE). Attaches ElementInternals and integrates with standard HTML forms. |
provide |
Map<any, any> | Record<string | symbol, any> |
W3C context provider map or object providing context down the DOM tree. |
consume |
string[] | Record<string, any> |
W3C context consumer declaration subscribing to context provided by an ancestor. |
onError |
(context: { error: Error, state: Record<string, any>, element?: any, page?: any, root?: any }) => string | { template?: string, state?: Record<string, any> } | void |
Component-level error boundary hook invoked on SSR rendering failures in production mode. |
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 Auto-Removal & State Preservation (
aria-*): When anaria-*attribute is bound with a single template token:-
Core ARIA State Attributes (
aria-expanded,aria-pressed,aria-checked,aria-selected): These 4 core attributes format falsy values (false,"false",0,"0") as"false"and preserve"mixed"where applicable. They are removed ONLY when bound values evaluate to nullish or empty (null,undefined,"","null","undefined"). -
Generic ARIA Attributes:
All other
aria-*attributes (e.g.,aria-hidden,aria-disabled,aria-label,aria-valuenow) are completely removed when falsy (false,"false",null,"null",undefined,"undefined",""), while preserving numeric0/"0".
-
Core ARIA State Attributes (
-
Boolean Custom Attributes:
When a custom element attribute is declared as a boolean type in its target component schema (via
Boolean,{ type: Boolean }, or{ type: 'Boolean' }, e.g.<atoll-button loading="{{ isCreating }}">whereloading: Boolean), template bindings automatically evaluate with boolean presence semantics. Falsy values (false,"false",null,undefined,"",0) cause the attribute to be completely removed from the DOM element, while truthy values render as an empty string presence attribute (e.g.loading=""). -
Standard Non-Boolean Custom Attributes: Standard custom or unreserved non-boolean attributes (e.g.
title="{{ label }}") are evaluated as string values (e.g.,title="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 functions used to calculate derived data. They are reactive; if an attribute or a data value changes, the getter automatically re-calculates. Getters support both synchronous pure functions and asynchronous functions returning Promises.
getters: {
visibleUsers: ({ state }) => state.users.slice(0, state.maxItems),
async filteredData: async ({ state, signal }) => {
const res = await fetch(`/api/filter?type=${state.filter}`, { signal })
return res.json()
}
}
When an asynchronous getter is evaluated or observed via observe(key, callback), Coralite tracks dependencies across await points and delivers resolved values to observers. If state changes while an async getter is in-flight, stale resolutions are automatically discarded to prevent race conditions.
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(). |
updateComplete |
Promise<boolean> |
A read-only Promise<boolean> that resolves when the element completes its current update cycle and flushes DOM changes and observers. Resolves immediately if idle; resolves to false if aborted, disconnected, or if the reactive cascade breaker trips. |
errors |
Record<string, string> |
Reactive dictionary mapping attribute names to validation error messages. |
internals |
ElementInternals | null |
The native ElementInternals instance attached when formAssociated: true is configured (null otherwise). |
setFormValue |
(value: any, state?: any) => void |
Sets the custom element's form submission value and state. Automatically synchronizes with state.value. |
setValidity |
(flags?: ValidityStateFlags, message?: string, anchor?: HTMLElement) => void |
Sets the custom element's validity flags, validation message, and focus anchor element. |
checkValidity |
() => boolean |
Checks if the element satisfies constraint validation without triggering browser UI popups. |
reportValidity |
() => boolean |
Checks constraint validation and displays browser validation bubble if invalid. |
validity |
ValidityState | undefined |
Live ValidityState getter object reflecting constraint validation. |
validationMessage |
string |
Live localized validation message string getter. |
form |
HTMLFormElement | null |
Live getter resolving the associated <form> element (either ancestor form or external form via form="id"). |
onFormReset |
(callback: () => void) => () => void |
Registers a callback invoked when the enclosing form is reset. Returns a disposer function. |
onFormDisabled |
(callback: (disabled: boolean) => void) => () => void |
Registers a callback invoked when form or ancestor <fieldset disabled> state changes. Returns a disposer function. |
onFormRestore |
(callback: (state: any, mode: 'restore' | 'autocomplete') => void) => () => void |
Registers a callback invoked when the browser restores form state or autocomplete occurs. Returns a disposer function. |
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));
}
}
7. formAssociated (Form-Associated Custom Elements) #
Coralite provides first-class, standard-aligned support for native Web Component Form-Associated Custom Elements (FACE). By configuring formAssociated: true in defineComponent, your custom element integrates directly with standard HTML <form> submission, FormData extraction, constraint validation, form reset cycles, and <fieldset disabled> cascading with zero third-party dependencies.
import { defineComponent } from 'coralite'
export default defineComponent({
formAssociated: true, // Enables FACE lifecycle and attachInternals()
attributes: {
name: String,
value: {
type: String,
default: '',
validate: (val) => (!val || val.length >= 3) || 'Value must be at least 3 characters'
},
disabled: Boolean
},
client: ({ state, setFormValue, onFormReset, onFormDisabled }) => {
// 1. Form value automatically synchronizes with state.value
// Calling setFormValue(customVal) manually overrides default serialization if needed.
// 2. Form reset hook: restores initial attribute/default snapshots
onFormReset(() => {
console.log('Form was reset!')
})
// 3. Fieldset disabled cascading
onFormDisabled((disabled) => {
console.log('Fieldset disabled state changed to:', disabled)
})
}
})
Opt-in Policy & Zero Platform Pollution #
FACE behavior is strictly opt-in to avoid prototype pollution and runtime overhead on standard components:
- Opt-In Enforcement: When
formAssociated: trueis specified, the compiler setsstatic formAssociated = trueon the generated custom element class, and Coralite invokesthis.attachInternals()during element construction. - Clean Standalone Components: If
formAssociated: trueis omitted or false,attachInternals()is never called,internalsisnull, andel.name/el.typeremain standard element properties. CallingsetFormValue()orsetValidity()on a non-form component emits a dev-mode warning.
Automatic Value Sync & Schema-to-Validity Bridge #
Coralite eliminates boilerplate when wiring up custom form controls by automatically synchronizing component state with native form APIs:
- Automatic
setFormValueSync: Writes tostate.valueautomatically update the element's form submission value viainternals.setFormValue(value). CallingsetFormValue(customValue, customState)inclient()provides an explicit manual override. - Schema-to-Validity Bridge: Attribute schema validation on
state.valueautomatically bridges into nativeElementInternals.setValidity():- When
attributes.value.validate(val)returns an error string (orfalse), Coralite automatically callsinternals.setValidity({ customError: true }, message, anchor), pointing to the internal<input>,<textarea>, or<select>if present in the component. - When errors clear, Coralite automatically resets validity to
{}(valid). - Explicit calls to
setValidity(flags, message, anchor)inclient()latch manually until cleared or reset.
- When
- Host Element Form Properties: Form-associated components expose standard DOM properties directly on the host custom element:
el.name: Reflects to/from thenameattribute.el.type: Returns the custom element's tag name.el.form: Resolves the associated<form>element (either ancestor form or external form matched byform="id").el.validity: Returns the currentValidityState.el.validationMessage: Returns the active validation message.el.willValidate: Indicates if the element participates in constraint validation.el.checkValidity()&el.reportValidity(): Executes constraint validation.el.labels: Returns aNodeListof associated<label>elements.
Form Lifecycle Hooks (onFormReset, onFormDisabled, onFormRestore) #
Coralite provides high-level reactive hooks in client() to handle native form callbacks gracefully:
onFormReset(callback): Fires when the enclosing form is reset via<button type="reset">orform.reset(). Coralite automatically restoresstate.valueandstate.checkedto their initial attribute/default snapshots, clearsstate.errors.value, resets validity, and executes all registeredonFormResetlisteners.onFormDisabled(callback): Fires whenever the component's disabled state changes, including when an ancestor<fieldset disabled>is toggled. Coralite automatically mirrors the disabled status tostate.disabled.onFormRestore(callback): Fires when the browser restores form state after navigation or during autofill, receiving(state, mode)where mode is'restore'or'autocomplete'.
8. onError (Component Error Boundary) #
The onError block provides component-level fault isolation for production rendering. If component script evaluation, getter computation, slot rendering, or template processing throws an error during SSR in mode: 'production', Coralite invokes onError to render fallback UI gracefully without destroying the host page.
onError({ error, state, element, page, root }) {
return {
template: '<div class="component-fallback"><p>{{ message }}</p></div>',
state: { message: 'Content temporarily unavailable' }
}
}
When an object with { template, state } is returned, the provided state properties are shallow-merged into the component state prior to parsing the fallback template string. Fallback HTML renders with noHydration: true and stripped data-cid hydration markers so browser clients do not attempt to hydrate failed SSR components. In development and testing modes (or if onError itself throws), errors bubble up to preserve immediate developer visibility and test assertion contracts.