Getting started โ
Mono UI is a small set of Lit-powered web components โ <mono-button>, <mono-input>, <mono-card>, etc. They're standard custom elements, so they work in Vue, React, Svelte, plain HTML, or anywhere custom elements run.
Install โ
Place below code inside your package.json after that just install with pnpm i. You'll need a GitHub token, lit is a peer dependency โ it ships separately so you can share one copy across the components and your own code.
json
{
"devDependencies": {
"lit": "^3.3.2",
"mono-helper": "git+https://<GITHUB_CLASSIC_TOKEN>@github.com/EJI-ICT/libs#path:/packages/mono-helper"
}
}Load the styles โ
Import the global stylesheet once, near the top of your app entry. It registers the CSS variables every component reads (colors, spacing, density, light/dark) and the scoped rules that paint each element.
ts
import 'mono-helper/ui/index.css'Tree-shakeable imports โ
Each component lives at its own subpath. Import only the ones you use โ the rest never enter your bundle.
ts
import 'mono-helper/ui/button'
import 'mono-helper/ui/input'
import 'mono-helper/ui/card'Importing the module is enough โ the file calls customElements.define('mono-โฆ', โฆ) as a side effect, and the tag becomes available everywhere.
Use in Vue โ
Two pieces of one-time setup are needed in vite.config.ts (or your VitePress config). Tell Vue to skip its component resolver for mono-* tags so it leaves them alone for the browser to handle:
ts
import vue from '@vitejs/plugin-vue'
export default {
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('mono-'),
},
},
}),
],
}Then any component renders just like an HTML element:
vue
<script setup>
import { ref } from 'vue'
import 'mono-helper/ui/input'
import 'mono-helper/ui/button'
const name = ref('')
</script>
<template>
<mono-input
label="Name"
:model-value="name"
@mno-input="name = $event.detail.modelValue"
></mono-input>
<mono-button color="primary" @click="alert(`Hello ${name}`)">
Say hi
</mono-button>
</template>A few Vue-specific gotchas:
v-modelon Lit elements silently misses the dispatched events. Bind:model-valueand listen for@mno-change/@mno-inputinstead, reading from$event.detail.modelValue.- For object/array props (
mono-menuitems,mono-selectoptions,cssClass), use the.propmodifier::items.prop="x". A plain:items="x"only sets a stringified attribute that Lit ignores. - For named slots, write
<el slot="name">โฆ</el>. Vue's<template #name>shorthand crashes the compiler on custom elements.