A lightweight, framework-agnostic Web Components library with everything you need to build modern web apps β without the bloat.
Most web component libraries force you into a choice: either you get a polished design system or you get app-level primitives like routing and state management.
@diniz/webcomponents gives you both β in a tiny, dependency-free package.
| Feature | @diniz/webcomponents | Shoelace | Material Web | Lightning Web Runtime |
|---|---|---|---|---|
| Routing with lazy loading | β Built-in | β | β | β |
| State management | β Store + Signals | β | β | β |
| Theme system | β CSS Variables + Custom | β | β | β |
| Bundle size | ~41KB gzipped | ~84KB | ~50KB | ~100KB+ |
| Framework agnostic | β | β | β | β Salesforce-only |
| TypeScript-first | β | β | β | β |
| Storybook docs | β | β | β | β |
npm install @diniz/webcomponents<script type="module">
import '@diniz/webcomponents';
</script>
<ui-button variant="primary" size="lg">
Get Started
</ui-button>
<ui-input
label="Email"
type="email"
placeholder="you@example.com"
required
></ui-input>
<ui-table id="users"></ui-table>
<script type="module">
const table = document.getElementById('users');
table.columns = [
{ key: 'name', label: 'Name', sortable: true },
{ key: 'email', label: 'Email' },
{ key: 'actions', label: 'Actions', actions: { edit: true, delete: true } }
];
table.rows = [
{ name: 'John Doe', email: 'john@example.com' },
{ name: 'Jane Smith', email: 'jane@example.com' }
];
</script>Build a single-page application with built-in routing and lazy loading:
Create index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My App</title>
<link rel="stylesheet" href="/src/styles/theme.css">
</head>
<body>
<nav>
<a href="/" data-link>Home</a>
<a href="/about" data-link>About</a>
<a href="/users" data-link>Users</a>
</nav>
<!-- Router outlet - components render here -->
<div id="app"></div>
<!-- Vite module entry point -->
<script type="module" src="/src/main.ts"></script>
</body>
</html>Create src/main.ts:
import '@diniz/webcomponents';
import { createRouter, applyTheme } from '@diniz/webcomponents';
// Define routes with lazy-loaded components
const routes = [
{
path: '/',
component: 'home-page',
load: () => import('./pages/home')
},
{
path: '/about',
component: 'about-page',
load: () => import('./pages/about')
},
{
path: '/users',
component: 'users-page',
load: () => import('./pages/users')
},
{
path: '/users/:id',
component: 'user-detail-page',
load: () => import('./pages/user-detail')
}
];
// Create router
const router = createRouter(routes);
// Apply theme
applyTheme('shadcn');
// Initialize router on page load
document.addEventListener('DOMContentLoaded', () => router());Create src/pages/home.ts:
import { LitComponent } from '@diniz/webcomponents';
import { html } from 'lit';
export class HomePage extends LitComponent {
render() {
return html`
<div class="page">
<h1>Welcome Home</h1>
<p>This is the home page.</p>
<ui-button @click=${() => this.navigate('/about')}>
Go to About
</ui-button>
</div>
`;
}
private navigate(path: string) {
history.pushState(null, '', path);
window.dispatchEvent(new PopStateEvent('popstate'));
}
}
customElements.define('home-page', HomePage);Create src/pages/users.ts:
import { LitComponent } from '@diniz/webcomponents';
import { html } from 'lit';
export class UsersPage extends LitComponent {
private users = [
{ id: 1, name: 'John Doe', email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
];
render() {
return html`
<div class="page">
<h1>Users</h1>
<ui-table
.columns=${[
{ key: 'name', label: 'Name', sortable: true },
{ key: 'email', label: 'Email' }
]}
.rows=${this.users}
></ui-table>
</div>
`;
}
}
customElements.define('users-page', UsersPage);Create src/pages/user-detail.ts:
import { LitComponent } from '@diniz/webcomponents';
import { html } from 'lit';
import { getPathParams } from '@diniz/webcomponents';
export class UserDetailPage extends LitComponent {
private userId: string | null = null;
connectedCallback() {
super.connectedCallback();
const params = getPathParams('/users/:id', location.pathname);
this.userId = params?.id ?? null;
}
render() {
return html`
<div class="page">
<h1>User Details</h1>
<p>User ID: ${this.userId}</p>
<ui-button @click=${() => history.back()}>
Go Back
</ui-button>
</div>
`;
}
}
customElements.define('user-detail-page', UserDetailPage);Update vite.config.ts:
import { defineConfig } from 'vite';
export default defineConfig({
server: {
port: 5173,
open: true
},
build: {
target: 'esnext',
outDir: 'dist'
}
});npm run devThe Vite dev server will:
- Serve
index.htmlas entry point - Handle TypeScript compilation automatically
- Lazy load page modules on navigation
- Support hot module replacement
- Lazy Loading β Pages load only when navigated to
- No Build Step for Components β Components render dynamically
- Type Safety β Full TypeScript support
- Real-time HMR β See changes instantly during development
- Automatic Bundling β Vite handles optimization
src/
βββ main.ts # Router setup
βββ pages/
β βββ home.ts # HomePage component
β βββ about.ts # AboutPage component
β βββ users.ts # UsersPage component
β βββ user-detail.ts # UserDetailPage component
βββ styles/
βββ theme.css # Global theme
index.html # Entry point
See Router Documentation for advanced features like route guards, path parameters, and base path configuration.
Icons: This library uses Feather Icons for all iconography.
- ui-input β Text, email, password with validation, icons, custom rules
- ui-select β Searchable dropdowns
- ui-checkbox β Custom styled checkboxes
- ui-radio β Radio buttons with descriptions
- ui-radio-group β Grouped radios with card variant
- ui-toggle-switch β iOS-style toggles
- ui-card β Versatile card with slots, variants, shadows
- ui-accordion β Collapsible sections
- ui-tabs β Animated tab navigation
- ui-modal β Accessible dialogs
- ui-sidebar β Navigation sidebar with icons
- ui-top-bar β Page header with actions
- ui-table β Sortable, resizable, expandable rows, actions
- ui-treeview β Hierarchical data with lazy loading
- ui-pagination β Page navigation
- ui-picklist β Dual-list selection
- ui-toast β Success, error, warning, info notifications
- ui-spinner β Loading indicators
- ui-tooltip β Hover/click tooltips
- ui-stepper β Multi-step flows
- ui-button β Variants, sizes, icons, loading states
- ui-link β Styled anchor links
- ui-dropdown β Menu dropdowns
- ui-date-picker β Calendar date selection
- ui-upload β File uploads
import { createRouter, createStore, applyTheme } from '@diniz/webcomponents';
// Built-in router with lazy loading
const router = createRouter([
{ path: '/', component: 'home-page', load: () => import('./pages/home') },
{ path: '/users/:id', component: 'user-page', load: () => import('./pages/user'), guards: [authGuard] }
]);
// Lightweight state management
const store = createStore({ user: null });
const { state, setState } = store;
setState('user', { name: 'John' });
// Multiple themes
applyTheme('shadcn'); // or 'zinc', 'rose', 'blue', 'green', 'orange', 'violet'
// Custom themes
registerCustomTheme({ name: 'my-app', url: '/themes/my-app.css' });
await applyTheme('my-app');| @diniz/webcomponents | Shoelace | |
|---|---|---|
| Routing | β Native | β External |
| State management | β Native | β External |
| Bundle size | ~41KB | ~84KB |
| Theming | CSS variables | CSS variables |
| Dependencies | None (lit only) | None (lit only) |
| @diniz/webcomponents | Material Web | |
|---|---|---|
| Routing | β Built-in | β External |
| State management | β Native | β External |
| Bundle size | ~41KB | ~50KB |
| Design | Clean, modern | Material Design 3 |
| Customization | Full CSS control | Limited theming |
| @diniz/webcomponents | LWR | |
|---|---|---|
| Routing | β Universal | β Salesforce-only |
| State management | β Universal | β Salesforce-only |
| Bundle size | ~41KB | ~100KB+ |
| Platform | Any framework | Salesforce only |
| Open source | β MIT | β Proprietary |
| @diniz/webcomponents | Custom | |
|---|---|---|
| Time to first component | 5 minutes | 2-3 days |
| Accessibility | β ARIA, keyboard | You decide |
| Theming | β Ready | Build yourself |
| Routing | β Included | Build yourself |
| State | β Included | Build yourself |
| Testing | β Included | Build yourself |
Most web component libraries are just component collections. They give you buttons and inputs but leave you to figure out:
- How to navigate between pages
- How to manage application state
- How to theme everything consistently
@diniz/webcomponents includes all the pieces you need for a complete app:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β @diniz/webcomponents β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Components β Routing β State β Theming β
β βββββββββββ β βββββββ β βββββ β βββββββ β
β β’ ui-button β β’ SPA β β’ Store β β’ CSS vars β
β β’ ui-input β β’ Lazy β β’ Signals β β’ 7 themes β
β β’ ui-table β β’ Guards β β β’ Custom β
β β’ ui-modal β β β β
β β’ ui-toast β β β β
β β’ ...20+ more β β β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Storybook β Interactive component playground with live demos and theme switching
- Component Documentation β Detailed guides:
- TABLE.md β Data table with sorting, pagination, and child rows
- SIDEBAR.md β Navigation sidebar with theming
- DATE_PICKER.md β Calendar date selection
- TOAST.md β Toast notifications
- TREEVIEW.md β Hierarchical tree with lazy loading
- HTTP_CLIENT.md β Lightweight fetch wrapper
- STYLING_GUIDE.md β Design patterns and styling
- Skills Documentation β Comprehensive AI agent skill guide with examples
- TypeScript β Full type definitions included
- Tests β 260+ tests covering all components
Works with anything that supports Custom Elements:
// Vanilla TypeScript
import '@diniz/webcomponents';
// React
import '@diniz/webcomponents';
<ui-button>Click me</ui-button>;
// Vue
import '@diniz/webcomponents';
<ui-button>Click me</ui-button>;
// Svelte
import '@diniz/webcomponents';
<ui-button>Click me</ui-button>;The library includes comprehensive AI agent skills for developers and AI assistants working with the components.
The skills are available for use with VS Code's GitHub Copilot:
-
Install the skill β It's automatically available when this project is open
-
Ask questions β Use natural language queries like:
- "How do I create a table with sorting and pagination?"
- "Show me how to validate form inputs"
- "Create a sidebar with custom theme colors"
- "How do I use the HTTP client?"
-
Get guidance β The skill provides:
- Component usage examples
- Validation patterns
- Theming and styling guidance
- API integration patterns
- Best practices
- Type definitions
- Component Reference β Complete API for 25+ components
- Code Examples β Copy-paste ready examples for all components
- Patterns β Common patterns for forms, tables, navigation, etc.
- Validation β Form validation and error handling patterns
- Theming β Theme system and customization guide
- HTTP Integration β API client usage and patterns
- State Management β Built-in store and signals guide
- Routing β Navigation and page management patterns
# Ask Copilot to help with a component
# "I need a data table that loads from an API with pagination and sorting"
# The skill provides:
# β
Complete HTML/JS example
# β
API integration code
# β
Event handling
# β
Error handling patterns
# β
TypeScript typesMIT β use it anywhere.