Skip to content

gersak/tyrell

Repository files navigation

"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 — maybe ty-button.

Yes! Let's call it ty."

Nine months later…

"Nine months in, ty still reads as 'thank you' — Just had to cut that and call it properly."

"The library is Tyrell. CLJS namespaces are tyrell.* now (tyrell.router, tyrell.components, tyrell.lucide). Component tags stay ty-* — web custom elements need the dash anyway, and two letters earn their keep. CSS classes stay ty-* for the same reason. The prefix earned the shortcut; the brand didn't."

"No thanks involved. Just replicants."

Tyrell

jsDelivr NPM Version Clojars Project

More framework than framework. Tyrell ships Web Components that work everywhere — React, Vue, HTMX, vanilla JS, ClojureScript.

Live Demo & Docs →

Why Tyrell?

Tyrell is a framework-agnostic evolution of Toddler, a ClojureScript UI library built on Helix (React).

Toddler provided great components (calendar, dropdown, routing, icons) but was locked to React/Helix. Tyrell takes that component library and rebuilds it with Web Components, making the same functionality available everywhere — React, Vue, HTMX, vanilla JS, and all ClojureScript frameworks (Replicant, UIx, Reagent).

Same components. Zero framework lock-in.


Load from CDN

Always loads the latest version:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tyrell-components/css/tyrell.css">
<script src="https://cdn.jsdelivr.net/npm/tyrell-components/dist/tyrell.js"></script>

Pin to a specific version (recommended for production):

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tyrell-components@1.0.0-RC6/css/tyrell.css">
<script src="https://cdn.jsdelivr.net/npm/tyrell-components@1.0.0-RC6/dist/tyrell.js"></script>

Browse all available versions on NPM or jsdelivr.

Then use components anywhere:

<ty-button flavor="primary">Click me</ty-button>
<ty-dropdown label="Country" placeholder="Select...">
  <ty-option value="us">United States</ty-option>
  <ty-option value="de">Germany</ty-option>
</ty-dropdown>

Using with AI coding agents

Tyrell is documented for AI agents from day one. Two artifacts make it work:

  • Agent instructions snippet — drop into your project's CLAUDE.md, .cursorrules, .windsurfrules, .github/copilot-instructions.md, or whichever instruction file your agent reads. The snippet teaches the agent the rules (colors come from Tyrell, events live on event.detail, icons need registration, etc.) and points at the doc index.
  • llms.txt — machine-readable index of every guide, served as raw markdown. Tell your agent to fetch it once and it has a navigable map of the entire documentation set. Per the llmstxt.org convention.

For agents with web fetch (Claude Code's WebFetch, Cursor's @web, ChatGPT browsing), pointing them at https://gersak.github.io/tyrell/llms.txt at session start is enough. For agents without it, paste the snippet into the instruction file and the agent learns the rules without any network calls.

The treasure-map entry point for AI navigation is guides/AI_GUIDE.md — two routing tables that get an agent to the right framework guide in one hop.


Guides

Pick the entry point for your stack:

JavaScript / TypeScript

  • Vanilla JS Guide — bundlers, subpath imports, icon tree-shaking, code splitting, SSR
  • React Guidetyrell-react wrappers
  • Vue Guide — Vue 3 / Nuxt native usage (no wrapper package)
  • Svelte Guide — Svelte 5 / SvelteKit native usage (no wrapper package)

ClojureScript

Server-driven UIs


ClojureScript

Add to deps.edn:

{:deps {dev.gersak/tyrell {:mvn/version "1.0.0-RC6"}}}   ; icons come transitively

That single dep brings:

  • Routing, i18n, layout, icon registry, shim — tyrell.router, tyrell.i18n, tyrell.layout, tyrell.icons, tyrell.shim
  • The tyrell.components shim that side-effect-imports the npm package
  • 12,000+ tree-shakeable icons (tyrell.lucide, tyrell.heroicons.*, tyrell.material.*, tyrell.fontawesome.*)

The npm tyrell-components package is declared in this artifact's deps.cljs, so shadow-cljs auto-installs it on first build.

Pick your view layer

You're using Guide
Reagent, re-frame, UIx, Helix QUICKSTART → Track Atyrell.react wrappers
Replicant, vanilla CLJS, server-rendered REPLICANT_TY_GUIDE — raw <ty-*> elements

Icon registration

<ty-icon name="check"> is a runtime registry lookup. Register the icons you reference at app startup:

(ns my-app.core
  (:require [tyrell.components]            ; side-effect: registers all <ty-*> elements
            [tyrell.icons :as icons]
            [tyrell.lucide :as lucide]
            [tyrell.heroicons.outline :as ho]))

(defn register-icons! []
  (icons/register!
    {:check  lucide/check
     :search lucide/search
     :user   ho/user-circle}))

Shadow-cljs :advanced removes unused icons automatically — you only pay for what you reference. See CLOJURESCRIPT_GUIDE → Icon registration.

Build Your Own Components

Use tyrell.shim to turn any ClojureScript render function into a Web Component:

(ns app.components
  (:require [replicant.dom :as d]
            [tyrell.shim :as shim]))

(defn greeting [name]
  [:div.ty-elevated.p-4.rounded-lg
   [:h2.ty-text+ "Hello, " name "!"]
   [:ty-button {:flavor "primary"} "Wave"]])

(defn render! [^js el]
  (d/render (shim/ensure-shadow el)
    (greeting (or (shim/attr el "name") "World"))))

(shim/define! "my-greeting"
  {:observed [:name]
   :connected render!
   :attr (fn [el _] (render! el))})
<my-greeting name="Clojure"></my-greeting>

Component Building Guide → | Code Splitting →


Components

Component Description
ty-button Semantic buttons with flavors, sizes, and icon slots
ty-input Text input with labels, validation, numeric formatting, debounce
ty-textarea Multi-line text with auto-resize and character count
ty-checkbox Styled checkbox with indeterminate state
ty-switch Toggle switch primitive
ty-radio-group / ty-radio Exclusive single-choice selection
ty-dropdown Searchable select with keyboard nav and mobile modal
ty-multiselect Multi-select with tags and search
ty-calendar Full calendar with date selection and form integration
ty-date-picker Calendar dropdown for date input
ty-tabs / ty-tab Carousel tabs with smooth animations
ty-wizard / ty-step Step-by-step wizard with progress tracking
ty-modal Native dialog with backdrop and focus management
ty-popup Anchored popover with smart positioning
ty-tooltip Hover tooltips with placement options
ty-icon SVG icons from Lucide, Heroicons, Material, FontAwesome
ty-tag Removable tags for selections
ty-copy Click-to-copy with visual feedback
ty-scroll-container Scrollable area with fade indicators
ty-resize-observer Self-observing element with debounce

See all components in action →


Links


MIT License

Packages

 
 
 

Contributors