defineComponent
Define a reusable template with a context factory, props, and slots.
Define a reusable template with a context factory, props, and slots.
Overview
The defineComponent function is used to define a Regor component, which encapsulates a part of your user interface (UI) with its own behavior and template. Components allow you to build complex UIs by composing smaller, reusable units.
Try it live
Ada Lovelace
Engineer
import {
computed,
defineComponent,
html,
ref,
unref,
type RefOrValue,
} from 'regor'
interface ProfileProps {
name: RefOrValue<string>
role: RefOrValue<string>
compact: RefOrValue<boolean>
}
export function createProfile(interactive = false) {
const ProfileCard = defineComponent<
ProfileProps & { initials: RefOrValue<string> }
>(
html` <article class="guide-profile" :class="{ 'is-compact': compact }">
<div class="guide-avatar" aria-hidden="true">{{ initials }}</div>
<div>
<h3>{{ name || 'Your name' }}</h3>
<p>{{ role }}</p>
</div>
<footer><slot name="footer"></slot></footer>
</article>`,
{
props: ['name', 'role', 'compact'],
context: (head) => {
head.enableSwitch = true // The named slot reads the parent's context.
return {
...head.props,
initials: computed(
() =>
unref(head.props.name)
.trim()
.split(/\s+/)
.slice(0, 2)
.map((word) => word[0] ?? '')
.join('')
.toUpperCase() || '?',
),
}
},
},
)
return {
interactive,
name: ref('Ada Lovelace'),
role: ref('Engineer'),
compact: ref(false),
available: ref(true),
components: { ProfileCard },
}
}
export const profileTemplate = html` <div class="guide-demo guide-demo--split">
<div class="guide-controls">
<label for="profile-name">Display name</label
><input
id="profile-name"
type="text"
maxlength="40"
r-model="name"
:disabled="!interactive"
/>
<label for="profile-role">Role</label
><select id="profile-role" r-model="role" :disabled="!interactive">
<option>Engineer</option>
<option>Designer</option>
<option>Researcher</option>
</select>
<label class="guide-check"
><input type="checkbox" r-model="compact" :disabled="!interactive" />
Compact layout</label
>
<label class="guide-check"
><input type="checkbox" r-model="available" :disabled="!interactive" />
Available for a project</label
>
</div>
<div class="guide-profile-preview">
<span class="guide-kicker">CHILD COMPONENT / LIVE PROPS</span>
<ProfileCard :name="name" :role="role" :compact="compact">
<template #footer
><span class="guide-slot-label">PARENT SLOT</span
><span
>{{ available ? 'Open to collaboration' : 'Focused on a project'
}}</span
></template
>
</ProfileCard>
</div>
</div>` import { createApp, RegorConfig, useScope } from 'regor'
import { apiExamples } from './examples'
const element = document.getElementById('api-demo')
const name = element?.dataset.example
if (element && name && Object.hasOwn(apiExamples, name)) {
const example = apiExamples[name as keyof typeof apiExamples]
const scope = useScope<object>(() => example.create(true))
const config =
'config' in scope.context && scope.context.config instanceof RegorConfig
? scope.context.config
: undefined
createApp(scope, { element, template: example.template }, config)
} The parent controls the form; the child receives props and a named slot.
Usage
Defining a Regor Component
To define a Regor component, call the defineComponent function with the following parameters:
-
template(required): An HTML string or an object specifying the template for rendering the component. It can include the following properties:selector(string, optional): A CSS selector string for the root element of the component. Regor will attempt to find this element in the DOM.element(Element, optional): A reference to the root DOM element of the component. If provided, this element will be used as the component's template.template(string, optional): An HTML string representing the initial content of the component's root element.json(object, optional): A JSON object representing the initial structure of the component's UI.isSVG(boolean, optional): Indicates whether the template contains SVG elements.
-
options(optional): An array of strings that defines component properties or an object that allows you to configure various options for the component, such as whether to use interpolation, props, the component's default name, or the component context.context(optional): A function that defines the Regor context for the component. This function receives aComponentHeadobject, which you can use to specify the component's behavior and props. It should return the Regor context.head.autoProps: Automatically mergeshead.propsinto the returned component context. Defaults totrue.head.entangle: Keeps refs defined in the component context entangled withhead.propsrefs. Defaults totrue.head.enableSwitch: Enables slot context switching to the parent. Defaults tofalse.head.onAutoPropsAssigned: Callback invoked after auto props get assigned to the component context.head.findContext(ContextClass, occurrence?): Finds a parent context instance byinstanceoffrom the captured context stack and returnsundefinedwhen missing.head.requireContext(ContextClass, occurrence?): Resolves a parent context instance byinstanceoffrom the captured context stack and throws if the selected occurrence is missing.head.validateProps(schema): Validates selected incoming props at runtime.head.unmount(): Unmounts this component range and runs unmounted handlers for captured contexts.
Example
import { defineComponent, createApp, html } from 'regor'
// Define a Regor component
const myComponent = defineComponent(
html`<div></div>`, // Define the component content from html string
{
context: (head) => ({
// Define the component's context and behavior here
// ... other context properties
}),
},
)
// Use the created component in your application
createApp({
components: { myComponent },
}) Parameters
-
template(required): An HTML string or an object specifying the template for rendering the component. It defines the component's UI structure, either by selecting an existing DOM element or providing HTML content or a JSON structure. -
options(optional): An array of strings that defines component properties or an object that configures various options for the component, including whether to use interpolation, props, the component's default name, or the component context.
Runtime prop validation
Inside context(head), you can validate incoming props explicitly:
import { defineComponent, html, pval } from 'regor'
type Card = {
title: string
count?: number
summary?: string
}
const Card = defineComponent<Card>(html`<article>{{ summary }}</article>`, {
props: ['title', 'count'],
context: (head) => {
head.validateProps({
title: pval.isString,
count: pval.optional(pval.isNumber),
})
return {
...head.props,
summary: `${head.props.title}:${head.props.count ?? 'none'}`,
}
},
}) Behavior:
- validates only the listed keys
- follows
config.propValidationMode - does not mutate
head.props - does not coerce values
Dynamic bindings and refs
Dynamic single-prop bindings such as :title="titleRef" arrive as refs. Validate them with pval.refOf(...):
type Card = {
title: Ref<string>
summary?: string
}
const Card = defineComponent<Card>(html`<article>{{ summary }}</article>`, {
props: ['title'],
context: (head) => {
head.validateProps({
title: pval.refOf(pval.isString),
})
return {
...head.props,
summary: head.props.title(),
}
},
}) For object-style :context="{ ... }" values, validate the object shape directly with pval.shape(...).
Validation mode
head.validateProps(...) follows the active RegorConfig.propValidationMode:
'throw'(default): throw on invalid prop'warn': warn and continue'off': disable runtime validation
Set it on the config passed to createApp(...).
Return Value
The defineComponent function returns a component object with the following properties:
-
context: The Regor context associated with the component. It defines the component's behavior, data, and reactivity. -
template: The template (root element) used for rendering the component's UI. -
inheritAttrs: A boolean indicating whether the component should inherit attributes from its parent. By default, it's set totrue. -
props: An optional object specifying the component's props, if any. This allows you to define input properties for your component. -
defaultName: An optional default name for the component. This name can be used for debugging and identification purposes.
Put component state inside its context factory. Separate instances then have separate state and cleanup.
Notes
-
Components are a fundamental building block in Regor applications. They encapsulate UI elements, logic, and reactivity, making it easier to manage complex user interfaces.
-
The
templateparameter specifies how the component's UI is rendered. You can select an existing element in the DOM, provide HTML content, or use a JSON structure to define the component's structure. -
For table-centric components (caption/section/row/cell/column components), component templates work with Regor's table preprocessing. Table containers (
table,caption,colgroup,thead,tbody,tfoot) and caption/section/row/cell/column placement are normalized to valid structure at runtime. -
Component tags can be used in PascalCase, camelCase, or kebab-case (for example,
<MyComponent>,<myComponent>, or<my-component>). -
The component context is configured through the
options.contextcallback, which defines the behavior and data of your component. -
Runtime prop validation is opt-in and local to
context(head)throughhead.validateProps(...). -
head.autoProps = truemergeshead.propsinto the returned component context and also keeps omitted declared prop names local by addingundefinedonly when the component did not already define that field. -
head.autoProps = falsedisables that merge. In that mode, omitted names are not added automatically, so normal parent-context lookup can still resolve them. -
The
optionsparameter allows you to configure various aspects of the component, such as enabling or disabling interpolation, specifying props, setting a default name, or providing the component context. -
Once a component is created, it can be used as a building block to construct your application's user interface.