quick start
This page assumes the project was created by pnpm create elfui@beta my-app --install. The scaffolding has been configured with the Vite plugin and generates src/main.ts, src/App.ts and vite.config.ts.
This page writes a counter component from scratch.
Prerequisites
This page uses ElfUI Macro components. Select Macro when creating the project and keep the Vite plugin configuration generated by the scaffold.
Recommended: install the VS Code extension
Use ElfUI Language Tools
Install ElfUI Language Tools for template completion, type information on hover, real-time diagnostics, go-to-definition, rename support, and snippets.
Search for ElfUI Language Tools in the VS Code Extensions view, or install it from the link above. It activates automatically when you open an ElfUI component in a .ts, .tsx, .js, or .jsx file.
Try it online
Do not want to set up a local environment first? Open the ElfUI Playground to edit, run, and preview an example in the browser. The link creates your own StackBlitz workspace and leaves the official starter unchanged.
Create component
// Counter.ts
import { defineHtml, useRef } from "@elfui/core";
const count = useRef(0);
const inc = (): void => count.set(count.peek() + 1);
export const Counter = defineHtml(`
<button class="counter" @click=${inc}>Count: ${count}</button>
`);The top-level code is the component’s setup logic. ${count} in the template will be compiled into responsive text binding, and @click=${inc} will become an event listener.
Current recommended syntax
Use defineHtml(\...`)anddefineStyle(`...`)directly. Beta.7 removes thehtmlandcss` tagged-template helpers; new projects and scaffold output use only the direct forms.
Mount application
// main.ts
import { createApp } from "@elfui/core";
import { Counter } from "./Counter";
createApp(Counter).mount("#app");index.html only needs an ordinary container and does not require handwritten component tags:
<div id="app"></div>Do not mount the root component twice
createApp(Counter).mount("#app") automatically registers the root component, creates an instance, and replaces the existing container content. Its return value is the actual Custom Element. The export name Counter is still inferred as elf-counter, but the application entry must not write that tag manually.
Register a component in existing HTML
If the component must be written directly into existing HTML, or a component library needs batch global registration, use registerComponents():
import { registerComponents } from "@elfui/core";
registerComponents(Counter);If you need to customize a single component name, you can use defineName(); if you need to unify the project prefix, please configure tagPrefix in the Vite plug-in.
Add style
import { defineHtml, defineStyle, useRef } from "@elfui/core";
defineStyle(`
.counter {
border: 0;
border-radius: 8px;
padding: 8px 12px;
}
`);
const count = useRef(0);
const inc = (): void => count.set(count.peek() + 1);
export const Counter = defineHtml(`
<button class="counter" @click=${inc}>Count: ${count}</button>
`);Styles are isolated by default
Component styles are injected into the current Custom Element's Shadow DOM, so they do not directly leak into the rest of the page.
Next step
- If you want to write a component API, see "Components".
- If you want to write template logic, see "Template Syntax" and "Directives".
- To access project diagnosis, see "Ecology/Vite Plug-in".
