"After playing around with Replicant, I realized I could build Web Components without React — actually, even without Replicant.
I'm wondering if it's called 'Replicant' because of Blade Runner (I love Blade Runner).
Maybe I could name my own library something similar... Tyrell? No, that feels pretentious.
Anyway, I don't really want to type something long like
tyrell-button. It should be shorter — maybety-button.Yes! Let's call it ty."
Framework-agnostic web components with a unique dual architecture:
Works with React, Vue, HTMX—or no framework at all.
ty is actively being developed. Components work in production, examples run smoothly, but expect rough edges. This is a real project with a real vision - web components that work everywhere, built on standards that won't break next year.
ty-text-- (faint) to ty-text++ (strong)<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My App</title>
<!-- Ty CSS and JS from CDN -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@gersak/ty/dist/ty.css">
<script src="https://cdn.jsdelivr.net/npm/@gersak/ty/dist/ty.js"></script>
</head>
<body>
<ty-button flavor="primary">Hello World</ty-button>
<ty-calendar value="2024-12-25"></ty-calendar>
</body>
</html>
npm install @gersak/ty
import '@gersak/ty/css/ty.css'
import { TyButton, TyCalendar } from '@gersak/ty'
Icons are optional and loaded separately:
// Import specific icons (tree-shakeable)
import { check, heart, save } from '@gersak/ty/icons/lucide'
// Register with global API
window.tyIcons.register({ check, heart, save })
Then use:
<ty-icon name="check"></ty-icon>
Available Icon Libraries:
⚠️ Import only what you need - importing all icons would load ~900KB!
For React projects, use the React wrapper package:
npm install @gersak/ty-react
import React, { useState } from 'react'
import { TyButton, TyInput, TyIcon } from '@gersak/ty-react'
import { check, heart, save } from '@gersak/ty/icons/lucide'
// Register icons
window.tyIcons.register({ check, heart, save })
function App() {
const [name, setName] = useState('')
return (
<div className="ty-elevated p-6 rounded-lg">
<h2 className="ty-text++ text-xl mb-4">Hello Ty!</h2>
<TyInput
value={name}
placeholder="Enter name"
onChange={(e) => setName(e.target.value)}
/>
<TyButton
flavor="primary"
onClick={() => alert('Hello ' + name)}
>
<TyIcon name="check" />
Submit
</TyButton>
</div>
)
}
Setup HTML (include Ty CSS and JS):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My React App</title>
<!-- Ty CSS and JS from CDN -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@gersak/ty/dist/ty.css">
<script src="https://cdn.jsdelivr.net/npm/@gersak/ty/dist/ty.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
<ty-input
hx-post="/api/search"
hx-trigger="input changed delay:300ms"
hx-target="#results"
placeholder="Search..."
/>
Just works. Server-side rendering with dynamic interactions.
Import the components, use them. Web Components are web standards.
For ClojureScript projects, use the React wrapper with tree-shakeable icon imports:
Add dependencies to deps.edn:
{:deps {com.pitch/uix.core {:mvn/version "1.1.0"}
com.pitch/uix.dom {:mvn/version "1.1.0"}
dev.gersak/ty-icons {:mvn/version "LATEST"} ; Tree-shakeable icons
dev.gersak/ty {:mvn/version "LATEST"}}} ; Optional: Router, i18n, layout
Import icons from ClojureScript (not JavaScript):
(ns my-app.core
(:require ["@gersak/ty-react" :as ty]
[ty.lucide :as lucide])) ; ← ClojureScript import, not JavaScript!
;; Register only the icons you need (Google Closure Compiler tree-shakes unused icons)
(js/window.tyIcons.register
#js {"check" lucide/check
"heart" lucide/heart
"save" lucide/save})
(defn app []
[:div.ty-elevated.p-6.rounded-lg
[:h2.ty-text++.text-xl.mb-4 "Hello Ty!"]
[:> ty/Button {:flavor "primary"
:on-click #(js/alert "Clicked!")}
[:> ty/Icon {:name "check"}]
"Submit"]])
⚠️ Important: Use ClojureScript imports for tree-shaking!
[ty.lucide :as lucide] - Google Closure Compiler eliminates unused icons["@gersak/ty/icons/lucide" :refer [check]] - Bundles ALL 1,636 icons (~897KB)By importing from the ClojureScript artifact (dev.gersak/ty-icons), only the icons you reference are included in your production bundle.
Bonus: Built-in router, i18n, and responsive layout system via dev.gersak/ty Clojars package.
Ty components require the ty.css stylesheet to display correctly. The CSS file contains:
.ty-bg-primary, .ty-text++, .ty-elevatedTypeScript Components (packages/core/)
@gersak/ty.d.ts type definitionsClojureScript Infrastructure (packages/cljs/)
dev.gersak/tyWhy This Matters:
This project grows with community input. Every issue, PR, and discussion helps shape the direction.
Ways to contribute:
Especially interested in:
Built with TypeScript for universal compatibility. Powered by ClojureScript for advanced features. Framework-agnostic by design.
MIT Licensed. Work in progress. Getting better every day.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |