defineComponent Plugin
The defineComponent plugin is Coralite's core built-in plugin that enables dynamic template functionality. It provides the wrapper for tokens, slots, and script execution in templates that need data processing and client-side interactivity.
What is defineComponent #
defineComponent is a built-in Coralite plugin enables data processing, computed values, or client-side Javascript. It's available as a core plugin from both coralite and coralite/plugins:
// Option 1: Import from coralite (core plugin)
import { defineComponent } from 'coralite'
// Option 2: Import from coralite/plugins (all plugins)
import { defineComponent } from 'coralite/plugins'
export default defineComponent({
// Component configuration
})
When to Use defineComponent #
Use defineComponent When: #
- Your template needs computed tokens (functions that process data)
- You need custom slot processing
- You need client-side JavaScript execution
- You need to use plugin methods inside the template
- Your template requires dynamic data binding
Do NOT Use defineComponent When: #
- Template only has simple token replacement (
{{ token }}) - No script processing is needed
- Template is purely static HTML
Template Type Comparison #
Static Template (No defineComponent) #
<template id="simple-component">
<div>
<h1>{{ title }}</h1>
<p>{{ description }}</p>
</div>
</template>
No script tag needed - Coralite processes token replacements automatically.
Dynamic Template (With defineComponent) #
<template id="dynamic-component">
<div>
<h1>{{ greeting }}</h1>
<button type="button" ref="actionBtn">Click me</button>
</div>
</template>
<script type="module">
import { defineComponent } from 'coralite'
export default defineComponent({
tokens: {
greeting: ({ name }) => `Hello, ${name}!`
},
script: (context, helpers) => {
const btn = helpers.refs('actionBtn')
btn.addEventListener('click', () => {
console.log('Button clicked!')
})
}
})
</script>
Requires defineComponent as the default export.
Basic Usage #
Here's the minimal setup for a dynamic template:
<template id="my-component">
<div>
<h1>{{ title }}</h1>
</div>
</template>
<script type="module">
import { defineComponent } from 'coralite'
export default defineComponent({
tokens: {
title: () => 'My Component Title'
}
})
</script>
Tokens #
Tokens are computed values that are processed at build time. They can be strings or functions that return values based on the template's context.
Token Structure #
export default defineComponent({
tokens: {
// Static token (string)
staticValue: 'Hello World',
// Computed token (function)
fullName: ({ firstName, lastName }) => `${firstName} ${lastName}`,
// Token with data processing
formattedDate: ({ date }) => new Date(date).toLocaleDateString(),
// Token with conditional logic
status: ({ isActive }) => isActive ? 'Active' : 'Inactive'
}
})
Token Context #
Token functions receive a values parameter containing:
- Page metadata: Values from
<meta>tags (prefixed with$) - Element attributes: Values from custom element attributes
<!-- Page: user.html -->
<head>
<meta name="firstName" content="Alice"></meta>
<meta name="lastName" content="Smith"></meta>
<title>User Profile</title>
</head>
<body>
<user-profile age="25"></user-profile>
</body>
// In defineComponent:
export default defineComponent({
tokens: {
// values = { $firstName: "Alice", $lastName: "Smith", $title: "User Profile", age: "25" }
fullName: ({ $firstName, $lastName }) => `${$firstName} ${$lastName}`,
greeting: ({ age }) => `You are ${age} years old`
}
})
Slots #
Slots allow you to process and transform content that is passed between custom element tags.
Basic Slot Processing #
<template id="card-component">
<div class="card">
<div class="card-content">
{{ content }}
</div>
</div>
</template>
<script type="module">
import { defineComponent } from 'coralite'
export default defineComponent({
slots: {
content: (slotNodes, values) => {
// Transform slot content
return slotNodes
}
}
})
</script>
Slot Function Parameters #
- slotNodes: Array of nodes from the slot content
- values: Current token values
Slot Example #
<!-- Using the component -->
<card-component>
<h2>Card Title</h2>
<p>Card content goes here</p>
</card-component>
// In defineComponent:
export default defineComponent({
slots: {
content: (slotNodes, values) => {
// Add classes or transform content
return slotNodes.map(node => {
if (node.type === 'tag' && node.name === 'h2') {
node.attribs.class = 'card-title'
}
return node
})
}
}
})
Script #
The script function provides client-side JavaScript execution. It gets serialized and runs in the browser after the page loads.
Script Function Signature #
export default defineComponent({
script: (context, helpers) => {
// context: Contains processed token values
// helpers: Contains client-side helpers like refs
// Return JavaScript code as string OR
return `
const btn = refs('actionBtn');
btn.addEventListener('click', () => {
console.log('Clicked!');
});
`
// OR execute directly (less common)
// (code runs immediately)
}
})
Script Context #
- context.values: Processed token values
- context.id: Unique instance identifier
Script Helpers #
- helpers.refs: DOM element access (see refs plugin documentation)
Script Example #
<template id="counter">
<div>
<h2>Count: {{ count }}</h2>
<button type="button" ref="increment">+</button>
<button type="button" ref="decrement">-</button>
</div>
</template>
<script type="module">
import { defineComponent } from 'coralite'
export default defineComponent({
tokens: {
count: ({ initial }) => parseInt(initial) || 0
},
script: (context, helpers) => {
const refs = helpers.refs
const increment = refs('increment')
const decrement = refs('decrement')
let count = context.values.count
increment.addEventListener('click', () => {
count++
document.querySelector('h2').textContent = `Count: ${count}`
})
decrement.addEventListener('click', () => {
count--
document.querySelector('h2').textContent = `Count: ${count}`
})
}
})
</script>
Complete Example #
Here's a complete example showing all defineComponent features working together:
<!-- Page: product.html -->
<head>
<meta name="name" content="Coralite Pro"></meta>
<meta name="price" content="99.99"></meta>
<meta name="inStock" content="true"></meta>
<title>Product Details</title>
</head>
<body>
<product-card discount="10" show-details="true"></product-card>
</body>
<!-- Template: product-card.html -->
<template id="product-card">
<div class="product-card">
<h2>{{ productName }}</h2>
<p class="price">{{ displayPrice }}</p>
<div class="status">{{ stockStatus }}</div>
<div class="details">
{{ details }}
</div>
<button type="button" ref="buyBtn">Buy Now</button>
</div>
</template>
<script type="module">
import { defineComponent } from 'coralite'
export default defineComponent({
tokens: {
// Computed token from page metadata
productName: ({ $name }) => $name,
// Computed token with calculation
displayPrice: ({ $price, discount }) => {
const price = parseFloat($price)
const discountPercent = parseFloat(discount) || 0
const finalPrice = price * (1 - discountPercent / 100)
return `$${finalPrice.toFixed(2)}`
},
// Conditional token
stockStatus: ({ $inStock }) =>
$inStock === 'true' ? 'In Stock' : 'Out of Stock'
},
slots: {
details: (slotNodes, values) => {
// Only show details if show-details attribute is true
if (values.showDetails !== 'true') {
return []
}
return slotNodes
}
},
script: (context, helpers) => {
const refs = helpers.refs
const buyBtn = refs('buyBtn')
if (buyBtn) {
buyBtn.addEventListener('click', () => {
alert(`Thank you for purchasing ${context.values.productName}!`)
})
}
}
})
</script>
Key Points #
- Tokens process page metadata and element attributes
- Slots control what content gets rendered
- Script adds interactivity after page load
- Helpers.refs provides safe DOM access