Interoperability
Interoperability
Section titled “Interoperability”Lift HTML is designed to work seamlessly with existing frameworks and libraries. This guide shows you how to integrate Lift HTML components with React, Vue, Angular, and other popular tools.
Framework Integration
Section titled “Framework Integration”React Integration
Section titled “React Integration”Lift HTML components can be used directly in React applications.
// React component using Lift HTMLimport React, { useEffect, useRef } from "react";import { defineComponent } from "lift-html";
// Define a Lift HTML componentconst Counter = defineComponent({ name: "lift-counter",
props: { initial: { type: Number, default: 0 }, },
data() { return { count: this.initial, }; },
template: ` <div class="counter"> <h3>Count: {{ count }}</h3> <button @click="increment">+</button> <button @click="decrement">-</button> <button @click="reset">Reset</button> </div> `,
methods: { increment() { this.count++; this.$emit("change", this.count); },
decrement() { this.count--; this.$emit("change", this.count); },
reset() { this.count = this.initial; this.$emit("change", this.count); }, },});
// Register the componentCounter.register();
// React wrapper componentconst LiftCounter = ({ initial = 0, onChange }) => { const counterRef = useRef(null);
useEffect(() => { if (counterRef.current) { const counter = counterRef.current;
// Listen for changes counter.addEventListener("change", (event) => { onChange?.(event.detail); }); } }, [onChange]);
return ( <div> <lift-counter ref={counterRef} initial={initial} /> </div> );};
// Usage in React appfunction App() { const [count, setCount] = useState(0);
return ( <div> <h1>React + Lift HTML</h1> <LiftCounter initial={5} onChange={setCount} /> <p>React state: {count}</p> </div> );}
Vue.js Integration
Section titled “Vue.js Integration”Lift HTML components work naturally with Vue.js.
// Vue.js component using Lift HTMLimport { defineComponent } from "lift-html";
const DataTable = defineComponent({ name: "lift-data-table",
props: { data: { type: Array, default: () => [] }, columns: { type: Array, default: () => [] }, },
template: ` <div class="data-table"> <table> <thead> <tr> <th v-for="column in columns" :key="column.key"> {{ column.label }} </th> </tr> </thead> <tbody> <tr v-for="row in data" :key="row.id"> <td v-for="column in columns" :key="column.key"> {{ row[column.key] }} </td> </tr> </tbody> </table> </div> `,});
DataTable.register();
<!-- Vue.js component --><template> <div> <h2>Vue + Lift HTML</h2> <lift-data-table :data="tableData" :columns="tableColumns" /> </div></template>
<script>export default { data() { return { tableData: [ { id: 1, name: 'John', email: 'john@example.com' }, { id: 2, name: 'Jane', email: 'jane@example.com' } ], tableColumns: [ { key: 'name', label: 'Name' }, { key: 'email', label: 'Email' } ] }; }};</script>
Angular Integration
Section titled “Angular Integration”Use Lift HTML components in Angular applications.
// Angular component using Lift HTMLimport { Component, ElementRef, OnInit } from "@angular/core";import { defineComponent } from "lift-html";
const Chart = defineComponent({ name: "lift-chart",
props: { data: { type: Array, default: () => [] }, type: { type: String, default: "bar" }, },
template: ` <div class="chart"> <canvas ref="chartCanvas"></canvas> </div> `,
mounted() { this.renderChart(); },
methods: { renderChart() { const canvas = this.$refs.chartCanvas; const ctx = canvas.getContext("2d");
// Chart rendering logic // This is a simplified example ctx.fillStyle = "#007bff"; this.data.forEach((item, index) => { ctx.fillRect(index * 50, 100 - item.value, 40, item.value); }); }, },
watch: { data() { this.renderChart(); }, },});
Chart.register();
@Component({ selector: "app-chart", template: ` <div> <h3>Angular + Lift HTML Chart</h3> <lift-chart [data]="chartData" type="bar" ></lift-chart> </div> `,})export class ChartComponent implements OnInit { chartData = [ { label: "A", value: 10 }, { label: "B", value: 20 }, { label: "C", value: 15 }, ];
constructor(private elementRef: ElementRef) {}
ngOnInit() { // Angular lifecycle management }}
Library Integration
Section titled “Library Integration”State Management (Redux, Zustand, etc.)
Section titled “State Management (Redux, Zustand, etc.)”// Lift HTML component with Redux integrationimport { defineComponent } from "lift-html";import { store } from "./store.js";
const TodoList = defineComponent({ name: "lift-todo-list",
data() { return { todos: [], newTodo: "", }; },
template: ` <div class="todo-list"> <input v-model="newTodo" @keyup.enter="addTodo" placeholder="Add a new todo" /> <button @click="addTodo">Add</button>
<ul> <li v-for="todo in todos" :key="todo.id"> <input type="checkbox" :checked="todo.completed" @change="toggleTodo(todo.id)" /> <span :class="{ completed: todo.completed }"> {{ todo.text }} </span> <button @click="removeTodo(todo.id)">Delete</button> </li> </ul> </div> `,
methods: { addTodo() { if (this.newTodo.trim()) { const todo = { id: Date.now(), text: this.newTodo, completed: false, };
// Dispatch to Redux store store.dispatch({ type: "ADD_TODO", payload: todo }); this.newTodo = ""; } },
toggleTodo(id) { store.dispatch({ type: "TOGGLE_TODO", payload: id }); },
removeTodo(id) { store.dispatch({ type: "REMOVE_TODO", payload: id }); }, },
mounted() { // Subscribe to store changes this.unsubscribe = store.subscribe(() => { this.todos = store.getState().todos; });
// Initial load this.todos = store.getState().todos; },
destroyed() { if (this.unsubscribe) { this.unsubscribe(); } },});
UI Libraries (Material-UI, Ant Design, etc.)
Section titled “UI Libraries (Material-UI, Ant Design, etc.)”// Lift HTML component styled with Material-UI classesimport { defineComponent } from "lift-html";
const MaterialButton = defineComponent({ name: "material-button",
props: { variant: { type: String, default: "contained" }, color: { type: String, default: "primary" }, disabled: { type: Boolean, default: false }, },
template: ` <button class="MuiButton-root MuiButton-{{ variant }} MuiButton-color{{ color }}" :disabled="disabled" @click="$emit('click')" > <slot></slot> </button> `,});
const MaterialCard = defineComponent({ name: "material-card",
props: { elevation: { type: Number, default: 1 }, },
template: ` <div class="MuiPaper-root MuiPaper-elevation{{ elevation }} MuiCard-root"> <div class="MuiCardContent-root"> <slot></slot> </div> </div> `,});
// Usageconst UserCard = defineComponent({ name: "user-card",
props: { user: { type: Object, required: true }, },
template: ` <material-card elevation="2"> <h3>{{ user.name }}</h3> <p>{{ user.email }}</p> <material-button variant="contained" color="primary" @click="editUser" > Edit </material-button> </material-card> `,
methods: { editUser() { this.$emit("edit", this.user); }, },});
Form Libraries (Formik, React Hook Form, etc.)
Section titled “Form Libraries (Formik, React Hook Form, etc.)”// Lift HTML component with Formik integrationimport { defineComponent } from "lift-html";
const FormField = defineComponent({ name: "form-field",
props: { name: { type: String, required: true }, label: { type: String, default: "" }, type: { type: String, default: "text" }, value: { type: String, default: "" }, error: { type: String, default: "" }, },
template: ` <div class="form-field"> <label v-if="label">{{ label }}</label> <input :type="type" :name="name" :value="value" @input="handleInput" @blur="handleBlur" :class="{ error: error }" /> <span v-if="error" class="error-message">{{ error }}</span> </div> `,
methods: { handleInput(event) { this.$emit("input", event.target.value); },
handleBlur(event) { this.$emit("blur", event); }, },});
// React component using Lift HTML with Formikconst FormikForm = () => { return ( <Formik initialValues={{ name: "", email: "" }} onSubmit={(values) => { console.log(values); }} > {({ values, handleChange, handleBlur, errors, touched }) => ( <form> <form-field name="name" label="Name" value={values.name} error={touched.name && errors.name} onInput={handleChange} onBlur={handleBlur} /> <form-field name="email" label="Email" type="email" value={values.email} error={touched.email && errors.email} onInput={handleChange} onBlur={handleBlur} /> <button type="submit">Submit</button> </form> )} </Formik> );};
Build Tool Integration
Section titled “Build Tool Integration”Vite Integration
Section titled “Vite Integration”import { defineConfig } from "vite";
export default defineConfig({ // Vite automatically handles ES modules // Lift HTML components work out of the box optimizeDeps: { include: ["lift-html"], },});
Webpack Integration
Section titled “Webpack Integration”module.exports = { // Webpack handles ES modules automatically // No special configuration needed for Lift HTML module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader", options: { presets: ["@babel/preset-env"], }, }, }, ], },};
TypeScript Integration
Section titled “TypeScript Integration”declare module "lift-html" { export interface ComponentOptions { name: string; props?: Record<string, any>; data?: () => Record<string, any>; template?: string; methods?: Record<string, Function>; lifecycle?: { created?: () => void; mounted?: () => void; updated?: () => void; destroyed?: () => void; }; }
export function defineComponent(options: ComponentOptions): any;}
// Usage with TypeScriptimport { defineComponent } from "lift-html";
interface User { id: number; name: string; email: string;}
const UserCard = defineComponent({ name: "user-card",
props: { user: { type: Object as () => User, required: true }, },
template: ` <div class="user-card"> <h3>{{ user.name }}</h3> <p>{{ user.email }}</p> </div> `,});
Best Practices
Section titled “Best Practices”Component Design for Interoperability
Section titled “Component Design for Interoperability”- Use Standard Web APIs: Leverage native browser APIs for better compatibility
- Emit Standard Events: Use custom events that frameworks can easily listen to
- Avoid Framework-Specific Code: Keep components framework-agnostic
- Provide Clear Interfaces: Use well-defined props and events
Performance
Section titled “Performance”// Lazy load components for better performanceconst LazyComponent = defineComponent({ name: "lazy-component",
data() { return { Component: null, loading: false, }; },
async mounted() { this.loading = true; const module = await import("./HeavyComponent.js"); this.Component = module.default; this.loading = false; },
template: ` <div> <div v-if="loading">Loading...</div> <Component v-else /> </div> `,});
Error Boundaries
Section titled “Error Boundaries”// Error boundary componentconst ErrorBoundary = defineComponent({ name: "error-boundary",
data() { return { hasError: false, error: null, }; },
template: ` <div> <div v-if="hasError" class="error-boundary"> <h3>Something went wrong</h3> <p>{{ error?.message }}</p> <button @click="reset">Try again</button> </div> <slot v-else></slot> </div> `,
methods: { reset() { this.hasError = false; this.error = null; }, },
mounted() { // Global error handler window.addEventListener("error", (event) => { this.hasError = true; this.error = event.error; }); },});
Next Steps
Section titled “Next Steps”- Best Practices - Learn advanced patterns and optimization
- Testing - Test your components effectively
- Deployment - Deploy your applications