Advanced Client-Side JavaScript
Coralite's component system allows you to bundle client-side logic directly with your HTML templates using the
defineComponent helper. This guide explains how to create interactive components, manage data flow,
and access DOM elements using the "Flat Options" API.
The defineComponent function is the core of Coralite's component logic. It separates server-side data
fetching and attribute coercion from client-side interactivity using four strictly isolated blocks.
import { defineComponent } from 'coralite'
import db from 'node:database' // Stripped from client bundle
export default defineComponent({
// Inputs: Coerced from HTML attributes
attributes: {
initialCount: { type: Number, default: 0 }
},
// Server-Side: Asynchronous data fetching (runs at build-time)
async data(context) {
const user = await db.users.findFirst();
return { userName: user.name }
},
// Derived State: Pure functions (Read-Only)
getters: {
greeting: (state) => `Hello, ${state.userName}!`
},
// Client-Side: Controller (Read/Write)
script({ state, signal, refs, ...pluginContext }) {
console.log('Component mounted for user:', state.userName)
const btn = refs('btn')
btn.addEventListener('click', () => {
state.initialCount++; // Reactive mutation
}, { signal });
}
})
The script block is executed in the browser when the component mounts. It receives a flattened context object via destructuring:
state: A Read/Write Reactive Proxy. This unified state contains state fromattributes,data, andgetters. Any mutation here triggers a re-render and re-evaluates getters.refs: A helper function to query DOM elements within the component's root that have arefattribute.signal: AnAbortSignaltied to the component's lifecycle. Always use this to clean up event listeners or abort pending fetch requests when the component unmounts.page: Static environment data including the current URL and file metadata.
Coralite uses a Lazy Deep Proxy system. Unlike frameworks that recursively make your entire data structure reactive upfront, Coralite only pays the performance cost for nested objects the exact moment they are accessed.
Additionally, Coralite follows the Smart State, Dumb Template philosophy. Instead of a Virtual DOM, Coralite performs direct token replacement ({{ key }}) in the template, making updates extremely fast and memory-efficient.
Because Coralite leverages standard ESM, you can use dynamic import() statements directly inside your script function to load client-side dependencies. These are automatically detected by the build tool and bundled for the browser.
export default defineComponent({
async script({ state, signal, refs, ...pluginContext }) {
const { default: confetti } = await import('https://esm.sh/canvas-confetti@1.6.0')
const btn = refs('celebrateBtn')
btn.addEventListener('click', () => {
confetti();
}, { signal })
}
})
Coralite encourages using standard Web APIs for component communication. Use CustomEvent to emit signals from a child to a parent. You can dispatch events from any element retrieved via refs.
// Inside a child component's script
script({ state, signal, refs, ...pluginContext }) {
const el = refs('main');
el.dispatchEvent(new CustomEvent('user-updated', {
bubbles: true,
detail: { name: 'Alice' }
}));
}