Installation
This library is a work-in-progress. We are releasing it early to gather feedback, but it is not ready for production.
AgnosticUI can be installed in two ways: using the AgnosticUI CLI (recommended) or as an npm package. Choose the approach that best fits your workflow.
AgnosticUI CLI (Recommended)
The AgnosticUI CLI provides a "local-first" approach where components are copied directly into your project. This gives you full ownership and control over the component code, making it easy to customize and extend components without worrying about breaking changes from upstream updates.
TypeScript Required
The CLI copies TypeScript (.ts) files containing decorators and type annotations. Your project must have a build tool that can compile TypeScript (e.g., Vite, webpack with ts-loader, or tsc). If your project uses plain JavaScript without TypeScript support, use the NPM Package approach instead.
Quick Start
Initialize AgnosticUI in your project root:
# Initialize with the CLI
npx agnosticui-cli initThe interactive CLI will guide you through:
- Selecting your framework (React, Vue, Lit, Svelte)
- Choosing where to generate components
- Installing required dependencies (
lit,@floating-ui/dom, etc.) - Configuring TypeScript (if detected)
CLI Command Variants
We recommend using npx agnosticui-cli since it works without requiring a global install. However, if you prefer the shorter npx ag variant, first install the CLI globally:
npm install -g agnosticui-cli@alphayarn global add agnosticui-cli@alphapnpm add -g agnosticui-cli@alphabun add -g agnosticui-cli@alphaAfter global installation, all npx agnosticui-cli commands can be replaced with npx ag (e.g., npx ag init, npx ag add button).
Note: If you have "The Silver Searcher" tool installed (which also uses the ag command), you may experience conflicts. In that case, stick with the full npx agnosticui-cli variant. :::
After Initialization
Follow the "Next Steps" printed by the CLI:
Import CSS Tokens
Add the following to your main entry file (e.g.,
main.ts,main.jsx):jsimport "./src/components/ag/styles/ag-tokens.css"; import "./src/components/ag/styles/ag-tokens-dark.css";Alternative: Use HTML Link Tags
You can also load the styles directly in your
index.html:html<link rel="stylesheet" href="/src/components/ag/styles/ag-tokens.css" /> <link rel="stylesheet" href="/src/components/ag/styles/ag-tokens-dark.css" />You can view the full list of theme tokens available in ag-tokens.css and ag-tokens-dark.css.
- Set Up Theming
Vite Default Dark Mode
Vite's default template uses a dark background (
#242424). You'll need to override this to use AgnosticUI's theme system.AgnosticUI uses a
data-themeattribute on the<html>element to control theming. Add this to your main CSS file or in a<style>tag:cssbody { background: var(--ag-background-primary); color: var(--ag-text-primary); transition: background 0.2s ease, color 0.2s ease; }Enable Dark Mode:
Add the
data-theme="dark"attribute to your<html>element:html<html lang="en" data-theme="dark"></html>Optional: Theme Toggle
Add a theme toggle button to your app:
html<button id="theme-toggle">Toggle Dark Mode</button> <script> const toggleBtn = document.getElementById("theme-toggle"); const html = document.documentElement; toggleBtn?.addEventListener("click", () => { const isDark = html.getAttribute("data-theme") === "dark"; if (isDark) { html.removeAttribute("data-theme"); } else { html.setAttribute("data-theme", "dark"); } }); </script>Add Components
Use the CLI to add the components you need:
bashnpx agnosticui-cli add button input cardUse Components
Import and use them in your app:
js// Below depends on where you are importing from. You will need // to adjust the relative path based on your project structure. import VueButton from "./src/components/ag/Button/vue/VueButton.vue";
Initialize AgnosticUI in your project:
npx agnosticui-cli init --framework vueReplace vue with your framework of choice: react, lit, or svelte.
This command will:
- Extract the AgnosticUI reference library to
./agnosticui/ - Create an
agnosticui.config.jsonconfiguration file - Set up design tokens in your components directory
- Install required dependencies
Required Dependencies
The CLI automatically installs these dependencies based on your framework:
All frameworks require:
lit- Core web components libraryfocus-trap- Used by Dialog and modal components for accessibility@floating-ui/dom- Used by Popover and Tooltip for positioning
React also requires:
@lit/react- Wrapper library for using Lit web components in React
Note on framework support:
- React and Vue have full framework-specific wrappers for all components
- Lit uses web components directly (no wrappers needed)
- Svelte and other frameworks use the Lit web components directly
Adding Components
Add components to your project:
# Add a single component
npx agnosticui-cli add button
# Add multiple components
npx agnosticui-cli add button input checkbox
# Overwrite existing components
npx agnosticui-cli add button --forceComponents are copied to ./src/components/ag/ by default (customizable with --components-path).
Listing Available Components
See all available components and which ones you've already added:
npx agnosticui-cli listProject Structure
After initialization, your project will have:
your-project/
├── agnosticui/ # Reference library (don't modify)
│ ├── lib/ # Component source files
│ ├── tokens/ # Design tokens
│ └── components.json # Component registry
├── src/
│ └── components/
│ └── ag/ # Your components (fully customizable)
│ ├── Button/
│ │ ├── core/ # Core Web Component
│ │ └── react/ # Framework wrapper (if applicable)
│ ├── Input/
│ └── styles/ # CSS tokens
│ ├── ag-tokens.css
│ └── ag-tokens-dark.css
└── agnosticui.config.json # CLI configurationUsing Components
Import components from your local components directory:
React
import { ReactButton } from "./components/ag/Button/react/ReactButton";
import { ReactInput } from "./components/ag/Input/react/ReactInput";
function App() {
return (
<>
<ReactButton variant="primary">Click me</ReactButton>
<ReactInput label="Email" type="email" />
</>
);
}Vue
<script setup>
import VueButton from "./components/ag/Button/vue/VueButton.vue";
import VueInput from "./components/ag/Input/vue/VueInput.vue";
</script>
<template>
<VueButton variant="primary">Click me</VueButton>
<VueInput label="Email" type="email" />
</template>Lit
import { html, LitElement } from "lit";
import "./components/ag/Button/core/Button";
import "./components/ag/Input/core/Input";
class MyApp extends LitElement {
render() {
return html`
<ag-button variant="primary">Click me</ag-button>
<ag-input label="Email" type="email"></ag-input>
`;
}
}Svelte / Other Frameworks
For Svelte, Angular, Solid, or other frameworks, use the Lit web components directly:
<script>
import './components/ag/Button/core/Button';
import './components/ag/Input/core/Input';
</script>
<ag-button variant="primary">Click me</ag-button>
<ag-input label="Email" type="email"></ag-input>CSS Tokens
The CLI automatically copies design tokens to ./src/components/ag/styles/. Import them in your application:
/* In your main CSS file */
@import "./components/ag/styles/ag-tokens.css";
/* Optional: Dark theme */
@import "./components/ag/styles/ag-tokens-dark.css";Or import in JavaScript:
// In your main entry file (e.g., main.tsx, main.ts)
import "./components/ag/styles/ag-tokens.css";
import "./components/ag/styles/ag-tokens-dark.css"; // OptionalConfiguration Options
Customize the CLI behavior with command-line flags:
# Specify a custom components path
npx agnosticui-cli init --framework vue --components-path ./src/ui/agnostic
# Use a local tarball (for development/testing)
npx agnosticui-cli init --framework vue --tarball /path/to/agnosticui-local-v0.0.1.tar.gzYour agnosticui.config.json will store these settings:
{
"version": "2.0.0-alpha",
"framework": "vue",
"paths": {
"reference": "./agnosticui",
"components": "./src/components/ag"
}
}Syncing Updates (Development)
During active development, you can sync the reference library with a new tarball:
npx agnosticui-cli sync --tarball /path/to/agnosticui-local-v0.0.2.tar.gzThis updates the reference library in ./agnosticui/ without touching your customized components.
TypeScript Configuration
If using TypeScript with Lit web components, enable experimental decorators in your TypeScript configuration (e.g., tsconfig.app.json or tsconfig.json):
{
"compilerOptions": {
"experimentalDecorators": true,
"useDefineForClassFields": false
}
}Note: If using Vite, these settings should only be in your TypeScript config, not in vite.config.ts under esbuild.tsconfigRaw. esbuild's implementation of experimental decorators is incomplete and can cause errors with Lit's @property decorator.
Vite Configuration
When using AgnosticUI with Vue and Vite, configure Vite to recognize <ag-*> components as custom elements in your vite.config.ts:
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith("ag-"),
},
},
}),
],
});This prevents Vue from treating AgnosticUI web components as Vue components.
NPM Package (Alternative)
For a more traditional approach, install AgnosticUI as an npm package. This method is suitable if you prefer using components as external dependencies.
Installation
Install the core package:
npm install agnosticui-coreyarn add agnosticui-corepnpm add agnosticui-corebun add agnosticui-coreInstall required dependencies based on your framework:
# All frameworks need these base dependencies
npm install lit focus-trap @floating-ui/dom
# React also needs
npm install @lit/react
# Install your framework's runtime if not already installed
npm install react react-dom # For React
npm install vue # For Vue# All frameworks need these base dependencies
yarn add lit focus-trap @floating-ui/dom
# React also needs
yarn add @lit/react
# Install your framework's runtime if not already installed
yarn add react react-dom # For React
yarn add vue # For Vue# All frameworks need these base dependencies
pnpm add lit focus-trap @floating-ui/dom
# React also needs
pnpm add @lit/react
# Install your framework's runtime if not already installed
pnpm add react react-dom # For React
pnpm add vue # For Vue# All frameworks need these base dependencies
bun add lit focus-trap @floating-ui/dom
# React also needs
bun add @lit/react
# Install your framework's runtime if not already installed
bun add react react-dom # For React
bun add vue # For VueUsing Components
Import components directly from the package:
React
import { ReactButton } from "agnosticui-core/button/react";
import { ReactInput } from "agnosticui-core/input/react";
function App() {
return (
<>
<ReactButton variant="primary">Click me</ReactButton>
<ReactInput label="Email" type="email" />
</>
);
}Vue
<script setup>
import { VueButton } from "agnosticui-core/button/vue";
import { VueInput } from "agnosticui-core/input/vue";
</script>
<template>
<VueButton variant="primary">Click me</VueButton>
<VueInput label="Email" type="email" />
</template>Lit
import "agnosticui-core/button";
import "agnosticui-core/input";
import { html, LitElement } from "lit";
class MyApp extends LitElement {
render() {
return html`
<ag-button variant="primary">Click me</ag-button>
<ag-input label="Email" type="email"></ag-input>
`;
}
}Svelte / Other Frameworks
<script>
import 'agnosticui-core/button';
import 'agnosticui-core/input';
</script>
<ag-button variant="primary">Click me</ag-button>
<ag-input label="Email" type="email"></ag-input>CSS Tokens
Import design tokens in your application:
// In your main entry file
import "agnosticui-core/styles/tokens.css";
import "agnosticui-core/styles/tokens-dark.css"; // Optional: Dark themeOr in CSS:
@import "agnosticui-core/styles/tokens.css";
@import "agnosticui-core/styles/tokens-dark.css"; /* Optional */Package Exports
The package provides granular exports for each component and framework:
// Core web components
import "agnosticui-core/button";
import "agnosticui-core/input";
// React wrappers
import { ReactButton } from "agnosticui-core/button/react";
import { ReactInput } from "agnosticui-core/input/react";
// Vue wrappers
import { VueButton } from "agnosticui-core/button/vue";
import { VueInput } from "agnosticui-core/input/vue";
// CSS tokens
import "agnosticui-core/styles/tokens.css";
import "agnosticui-core/styles/tokens-dark.css";Troubleshooting
Decorator Support (Preact, Solid, Babel-based frameworks)
If using Preact, Solid, or other frameworks that rely on Babel for JSX transformation, you may encounter decorator errors. Fix by excluding AgnosticUI files from Babel and adding TypeScript declarations:
1. Update vite.config.ts:
import { defineConfig } from 'vite'
import preact from '@preact/preset-vite' // or your framework plugin
export default defineConfig({
plugins: [
preact({
exclude: [/\/components\/ag\//], // Let esbuild handle AgnosticUI files
})
],
})2. Create src/components/ag/ag-elements.d.ts:
declare namespace preact.JSX {
interface IntrinsicElements {
'ag-button': {
variant?: string;
size?: string;
onClick?: () => void;
children?: preact.ComponentChildren;
};
// Add other ag-* elements as needed
}
}Finding Component Props
Each component exports a Props interface you can reference. For example, see ButtonProps in src/components/ag/Button/core/_Button.ts for all available button properties and their types.
Comparison: CLI vs NPM
| Feature | CLI (Recommended) | NPM Package |
|---|---|---|
| Setup | npx agnosticui-cli init | npm install agnosticui-core |
| Component Location | Local in your project | node_modules |
| Customization | Full control - edit freely | Limited - must extend/wrap |
| Updates | Manual - copy new versions | Automatic - npm update |
| Bundle Size | Only components you use | Tree-shakeable |
| TypeScript | Required (copies .ts files) | Full type definitions |
| Build Tool | Must support TS compilation | Any modern bundler |
| Best For | TS projects needing customization | Quick prototyping, JS projects |
Framework Support
AgnosticUI provides different levels of support for each framework:
| Framework | Support Level | Implementation |
|---|---|---|
| React | Full | Framework-specific wrappers for all components |
| Vue | Full | Framework-specific wrappers for all components |
| Lit | Full | Direct web component usage |
| Svelte | Basic | Direct web component usage |
| Angular | Basic | Direct web component usage |
| Solid | Basic | Direct web component usage |
| Other | Basic | Direct web component usage |
All frameworks can use the underlying Lit web components. React and Vue have additional framework-specific wrappers for a more native development experience.