hybrids
Extraordinary JavaScript UI framework with unique declarative and functional architecture
Top Related Projects
Lit is a simple library for building fast, lightweight web components.
A toolchain for building scalable, enterprise-ready component systems on top of TypeScript and Web Component standards. Stencil components can be distributed natively to React, Angular, Vue, and traditional web developers from a single, framework-agnostic codebase.
LEGACY REPO. This repository is for maintenance of the legacy LitElement library. The LitElement base class is now part of the Lit library, which is developed in the lit monorepo.
Cybernetically enhanced web apps
Deliver web apps with confidence 🚀
This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
Quick Overview
Hybrids is a UI library for creating web components with a unique, functional approach. It combines the simplicity of functional programming with the expressiveness of web components, offering a lightweight and efficient solution for building modern web interfaces.
Pros
- Simple and intuitive API for creating web components
- Excellent performance due to its optimized update algorithm
- Small bundle size (about 4KB gzipped) with no dependencies
- Seamless integration with other frameworks and vanilla JavaScript
Cons
- Smaller community compared to more established UI libraries
- Limited ecosystem of pre-built components
- Learning curve for developers unfamiliar with functional programming concepts
- Less suitable for large, complex applications compared to full-featured frameworks
Code Examples
- Creating a simple counter component:
import { html, define } from 'hybrids';
function increment(host) {
host.count += 1;
}
export default define({
tag: 'simple-counter',
count: 0,
render: ({ count }) => html`
<button onclick="${increment}">Count: ${count}</button>
`,
});
- Using property descriptors for computed properties:
import { html, define } from 'hybrids';
export default define({
tag: 'user-profile',
name: '',
age: 0,
fullDescription: {
get: ({ name, age }) => `${name} is ${age} years old`,
},
render: ({ fullDescription }) => html`
<p>${fullDescription}</p>
`,
});
- Handling asynchronous data:
import { html, define } from 'hybrids';
function fetchData(host) {
return fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => { host.data = data; });
}
export default define({
tag: 'async-component',
data: {
get: fetchData,
observe: (host, value) => console.log('Data updated:', value),
},
render: ({ data }) => html`
<ul>
${data ? data.map(item => html`<li>${item}</li>`) : html`<li>Loading...</li>`}
</ul>
`,
});
Getting Started
To start using Hybrids, follow these steps:
-
Install Hybrids via npm:
npm install hybrids
-
Create a new component file (e.g.,
my-component.js
):import { html, define } from 'hybrids'; export default define({ tag: 'my-component', name: '', render: ({ name }) => html` <h1>Hello, ${name || 'World'}!</h1> `, });
-
Use the component in your HTML:
<script type="module" src="./my-component.js"></script> <my-component name="Hybrids"></my-component>
That's it! You've created and used your first Hybrids component.
Competitor Comparisons
Lit is a simple library for building fast, lightweight web components.
Pros of Lit
- Larger community and ecosystem, with more resources and third-party libraries
- Backed by Google, ensuring long-term support and development
- Better performance for complex applications with many components
Cons of Lit
- Steeper learning curve, especially for developers new to web components
- More verbose syntax compared to Hybrids' declarative approach
- Requires a build step for optimal performance and browser compatibility
Code Comparison
Lit example:
import {LitElement, html} from 'lit';
class MyElement extends LitElement {
render() {
return html`<p>Hello, World!</p>`;
}
}
customElements.define('my-element', MyElement);
Hybrids example:
import {html, define} from 'hybrids';
const MyElement = {
render: () => html`<p>Hello, World!</p>`
};
define('my-element', MyElement);
Both Lit and Hybrids are libraries for creating web components, but they differ in their approach and syntax. Lit offers a more traditional class-based structure, while Hybrids uses a simpler, object-based approach. Lit is generally better suited for larger, more complex applications, while Hybrids shines in simplicity and ease of use for smaller projects or developers new to web components.
A toolchain for building scalable, enterprise-ready component systems on top of TypeScript and Web Component standards. Stencil components can be distributed natively to React, Angular, Vue, and traditional web developers from a single, framework-agnostic codebase.
Pros of Stencil
- Generates highly optimized, framework-agnostic Web Components
- Includes a powerful set of build tools and optimizations out-of-the-box
- Offers TypeScript support and static type checking
Cons of Stencil
- Steeper learning curve due to its comprehensive toolset
- Larger bundle size compared to Hybrids' minimal approach
- Requires a build step, which may complicate the development process
Code Comparison
Stencil component:
import { Component, Prop, h } from '@stencil/core';
@Component({
tag: 'my-component',
styleUrl: 'my-component.css',
shadow: true,
})
export class MyComponent {
@Prop() name: string;
render() {
return <div>Hello, {this.name}!</div>;
}
}
Hybrids component:
import { html, define } from 'hybrids';
export const MyComponent = {
name: '',
render: ({ name }) => html`<div>Hello, ${name}!</div>`,
};
define('my-component', MyComponent);
The Stencil example uses TypeScript and decorators, while Hybrids employs a more functional approach with plain JavaScript objects. Stencil's syntax is closer to React, whereas Hybrids uses a unique property-based definition style.
LEGACY REPO. This repository is for maintenance of the legacy LitElement library. The LitElement base class is now part of the Lit library, which is developed in the lit monorepo.
Pros of lit-element
- Larger community and ecosystem, with more resources and third-party libraries
- Backed by Google, ensuring long-term support and development
- Seamless integration with other Google web technologies
Cons of lit-element
- Steeper learning curve for developers new to Web Components
- More verbose syntax compared to Hybrids' declarative approach
- Requires a build step for optimal performance
Code Comparison
lit-element:
import { LitElement, html } from 'lit-element';
class MyElement extends LitElement {
render() {
return html`<p>Hello, World!</p>`;
}
}
customElements.define('my-element', MyElement);
Hybrids:
import { html, define } from 'hybrids';
const MyElement = {
render: () => html`<p>Hello, World!</p>`,
};
define('my-element', MyElement);
Both lit-element and Hybrids are libraries for creating Web Components, but they differ in their approach and syntax. lit-element uses a class-based structure and extends LitElement, while Hybrids employs a more functional and declarative style. The choice between them often depends on personal preference, project requirements, and team expertise.
Cybernetically enhanced web apps
Pros of Svelte
- Compiler-based approach results in smaller bundle sizes and better runtime performance
- More mature ecosystem with a larger community and more available resources
- Built-in state management and animation capabilities
Cons of Svelte
- Requires a build step, which can complicate the development process
- Less flexible than Hybrids for integrating with existing JavaScript codebases
- Steeper learning curve for developers familiar with traditional frameworks
Code Comparison
Svelte component:
<script>
export let name = 'World';
</script>
<h1>Hello {name}!</h1>
Hybrids component:
import { html } from 'hybrids';
export default {
name: 'World',
render: ({ name }) => html`<h1>Hello ${name}!</h1>`,
};
Both Svelte and Hybrids offer concise ways to create components, but Svelte uses a more template-like syntax, while Hybrids leverages JavaScript's template literals. Svelte's approach may be more familiar to developers coming from traditional frameworks, while Hybrids' syntax is closer to native JavaScript.
Deliver web apps with confidence 🚀
Pros of Angular
- Comprehensive framework with a full ecosystem of tools and libraries
- Strong TypeScript support and dependency injection system
- Extensive documentation and large community support
Cons of Angular
- Steeper learning curve due to its complexity
- Heavier bundle size compared to lightweight alternatives
- More opinionated, which can limit flexibility in some cases
Code Comparison
Angular component:
@Component({
selector: 'app-hello',
template: '<h1>Hello, {{name}}!</h1>'
})
export class HelloComponent {
@Input() name: string;
}
Hybrids component:
export default define({
tag: 'hello-component',
name: '',
render: ({ name }) => html`<h1>Hello, ${name}!</h1>`
});
Key Differences
- Angular uses a class-based approach with decorators, while Hybrids uses a more functional style
- Angular requires a separate template, whereas Hybrids combines the template with the component definition
- Hybrids has a simpler API and smaller learning curve compared to Angular's more complex structure
- Angular offers more built-in features and tooling, while Hybrids focuses on being lightweight and flexible
Both frameworks have their strengths, with Angular being more suitable for large-scale applications and Hybrids offering a simpler alternative for smaller projects or those preferring a lightweight approach.
This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
Pros of Vue
- Larger ecosystem and community support
- More comprehensive documentation and learning resources
- Offers a full-featured framework with built-in state management and routing
Cons of Vue
- Steeper learning curve for beginners
- Heavier bundle size compared to Hybrids
- More opinionated structure, which may limit flexibility in some cases
Code Comparison
Vue component:
export default {
data() {
return { count: 0 }
},
methods: {
increment() {
this.count++
}
},
template: '<button @click="increment">{{ count }}</button>'
}
Hybrids component:
import { html, define } from 'hybrids';
export default define({
count: 0,
render: ({ count }) => html`
<button onclick="${host => host.count += 1}">${count}</button>
`,
});
Vue uses a more traditional object-based component definition with separate data, methods, and template sections. Hybrids employs a more functional approach, combining state and rendering in a single object. The Hybrids syntax is generally more concise, while Vue's structure may be more familiar to developers coming from other frameworks.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
An extraordinary JavaScript framework for creating client-side web applications, UI components libraries, or single web components with unique mixed declarative and functional architecture
Hybrids provides a complete set of features for building modern web applications:
- Component Model based on plain objects and pure functions
- Global State Management with external storages, offline caching, relations, and more
- App-like Routing based on the graph structure of views
- Layout Engine making UI layouts development much faster
- Localization with automatic translation of the templates content
- Hot Module Replacement support without any additional configuration
Documentation
The project documentation is available at the hybrids.js.org site.
Quick Look
Component Model
It's based on plain objects and pure functions1, still using the Web Components API under the hood:
import { html, define } from "hybrids";
function increaseCount(host) {
host.count += 1;
}
export default define({
tag: "simple-counter",
count: 0,
render: ({ count }) => html`
<button onclick="${increaseCount}">
Count: ${count}
</button>
`,
});
<simple-counter count="42"></simple-counter>
You can read more in the Component Model section.
Global State Management
A global state management uses declarative model definitions with support for async external storages, relations, offline caching, and many more:
import { define, store, html } from "hybrids";
const User = {
id: true,
firstName: "",
lastName: "",
[store.connect] : {
get: id => fetch(`/users/${id}`).then(...),
},
};
define({
tag: "user-details",
user: store(User),
render: ({ user }) => html`
<div>
${store.pending(user) && `Loading...`}
${store.error(user) && `Something went wrong...`}
${store.ready(user) && html`
<p>${user.firstName} ${user.lastName}</p>
`}
</div>
`,
});
<user-details user="2"></user-details>
You can read more in the Store section.
App-like Routing
Rather than just matching URLs with the corresponding components, the router depends on a tree-like structure of views, which have their own routing configuration. It makes the URLs optional, have out-the-box support for dialogs, protected views, and many more.
import { define, html, router } from "hybrids";
import Details from "./details.js";
const Home = define({
[router.connect]: { stack: [Details, ...] },
tag: "app-home",
render: () => html`
<template layout="column">
<h1>Home</h1>
<nav layout="row gap">
<a href="${router.url(Details)}">Details</a>
</nav>
...
</template>
`,
});
export define({
tag: "app-router",
stack: router(Home),
render: ({ stack }) => html`
<template layout="column">
${stack}
</template>
`,
});
<app-router></app-router>
You can read more in the Router section.
Layout Engine
Create CSS layouts in-place in templates, even without using Shadow DOM, but still keeping the encapsulation of the component's styles:
define({
tag: "app-home-view",
render: () => html`
<template layout="column center gap:2">
<div layout="grow grid:1|max">
<h1>Home</h1>
...
</div>
<footer layout@768px="hidden">...</footer>
</template>
`
});
You can read more in the Layout Engine section of the documentation.
Localization
The library supports automatic translation of the component's content, which makes translation seamless and easy to integrate. Additionally, it provides a way to add dynamic messages with plural forms, HTML content, or use messages outside of the template context. Also, it comes with handy CLI tool to extract messages from the source code!
import { define, html, localize } from "hybrids";
export default define({
tag: "my-element",
name: "",
render: ({ name }) => html`
<div>Hello ${name}!</div>
`,
});
localize("pl", {
"Hello ${0}!": {
message: "Witaj ${0}!",
},
});
You can read more in the Localization section of the documentation.
Community
Do you need help? Something went wrong? Feel free to create an issue in the github repository or join the Gitter channel.
License
Hybrids is released under the MIT License.
Footnotes
-
Pure functions only apply to the component definition. Side effects attached to event listeners might mutate the host element. ↩
Top Related Projects
Lit is a simple library for building fast, lightweight web components.
A toolchain for building scalable, enterprise-ready component systems on top of TypeScript and Web Component standards. Stencil components can be distributed natively to React, Angular, Vue, and traditional web developers from a single, framework-agnostic codebase.
LEGACY REPO. This repository is for maintenance of the legacy LitElement library. The LitElement base class is now part of the Lit library, which is developed in the lit monorepo.
Cybernetically enhanced web apps
Deliver web apps with confidence 🚀
This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot