{"id":49850562,"url":"https://github.com/gersak/tyrell","last_synced_at":"2026-06-20T08:31:17.298Z","repository":{"id":346356541,"uuid":"1161674553","full_name":"gersak/tyrell","owner":"gersak","description":"Clojurescript WebComponents library","archived":false,"fork":false,"pushed_at":"2026-06-02T11:44:49.000Z","size":37066,"stargazers_count":27,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-06-02T12:14:42.569Z","etag":null,"topics":["clojurescript","htmx","mobile","react","webcomponents","zero-dependency"],"latest_commit_sha":null,"homepage":"https://gersak.github.io/tyrell/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gersak.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-19T11:37:23.000Z","updated_at":"2026-06-02T11:05:57.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/gersak/tyrell","commit_stats":null,"previous_names":["gersak/ty","gersak/tyrell"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/gersak/tyrell","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gersak%2Ftyrell","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gersak%2Ftyrell/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gersak%2Ftyrell/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gersak%2Ftyrell/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gersak","download_url":"https://codeload.github.com/gersak/tyrell/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gersak%2Ftyrell/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34563535,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-20T02:00:06.407Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojurescript","htmx","mobile","react","webcomponents","zero-dependency"],"created_at":"2026-05-14T15:43:04.485Z","updated_at":"2026-06-20T08:31:17.290Z","avatar_url":"https://github.com/gersak.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cblockquote style=\"color: #414863\"\u003e\n\u003cp\u003e\u003cem\u003e\"After playing around with Replicant, I realized I could build Web Components without React — actually, even without Replicant.\u003c/em\u003e\u003c/p\u003e\n\n\u003cp\u003e\u003cem\u003eI'm wondering if it's called 'Replicant' because of \u003cstrong\u003eBlade Runner\u003c/strong\u003e (I love Blade Runner).\u003c/em\u003e\u003c/p\u003e\n\n\u003cp\u003e\u003cem\u003eMaybe I could name my own library something similar... Tyrell? No, that feels pretentious.\u003c/em\u003e\u003c/p\u003e\n\n\u003cp\u003e\u003cem\u003eAnyway, I don't really want to type something long like \u003ccode\u003etyrell-button\u003c/code\u003e. It should be shorter — maybe \u003ccode\u003ety-button\u003c/code\u003e.\u003c/em\u003e\u003c/p\u003e\n\n\u003cp\u003e\u003cstrong\u003e\u003cem\u003eYes! Let's call it ty.\"\u003c/em\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\n\u003cblockquote style=\"color: #414863\"\u003e\n\u003cp\u003e\u003cem\u003eNine months later…\u003c/em\u003e\u003c/p\u003e\n\n\u003cp\u003e\u003cem\u003e\"Nine months in, \u003cstrong\u003ety\u003c/strong\u003e still reads as \u003cstrong\u003e'thank you'\u003c/strong\u003e — Just had to cut that and call it properly.\"\u003c/em\u003e\u003c/p\u003e\n\n\u003cp\u003e\u003cem\u003e\"The library is \u003cstrong\u003eTyrell\u003c/strong\u003e. CLJS namespaces are \u003ccode\u003etyrell.*\u003c/code\u003e now (\u003ccode\u003etyrell.router\u003c/code\u003e, \u003ccode\u003etyrell.components\u003c/code\u003e, \u003ccode\u003etyrell.lucide\u003c/code\u003e). Component tags stay \u003ccode\u003ety-*\u003c/code\u003e — web custom elements need the dash anyway, and two letters earn their keep. CSS classes stay \u003ccode\u003ety-*\u003c/code\u003e for the same reason. The prefix earned the shortcut; the brand didn't.\"\u003c/em\u003e\u003c/p\u003e\n\n\u003cp\u003e\u003cstrong\u003e\u003cem\u003e\"No thanks involved. Just replicants.\"\u003c/em\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\n# Tyrell\n\n[![jsDelivr](https://data.jsdelivr.com/v1/package/npm/tyrell-components/badge)](https://www.jsdelivr.com/package/npm/tyrell-components)\n[![NPM Version](https://img.shields.io/npm/v/tyrell-components.svg)](https://www.npmjs.com/package/tyrell-components)\n[![Clojars Project](https://img.shields.io/clojars/v/dev.gersak/tyrell.svg)](https://clojars.org/dev.gersak/tyrell)\n\n**More framework than framework.** Tyrell ships Web Components that work everywhere — React, Vue, HTMX, vanilla JS, ClojureScript.\n\n**[Live Demo \u0026 Docs →](https://gersak.github.io/tyrell)**\n\n## Why Tyrell?\n\nTyrell is a **framework-agnostic evolution of [Toddler](https://github.com/gersak/toddler)**, a ClojureScript UI library built on Helix (React).\n\nToddler 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).\n\nSame components. Zero framework lock-in.\n\n---\n\n## Load from CDN\n\nAlways loads the latest version:\n\n```html\n\u003clink rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/tyrell-components/css/tyrell.css\"\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/tyrell-components/dist/tyrell.js\"\u003e\u003c/script\u003e\n```\n\nPin to a specific version (recommended for production):\n\n```html\n\u003clink rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/tyrell-components@1.0.0-RC10/css/tyrell.css\"\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/tyrell-components@1.0.0-RC10/dist/tyrell.js\"\u003e\u003c/script\u003e\n```\n\nBrowse all available versions on [NPM](https://www.npmjs.com/package/tyrell-components?activeTab=versions) or [jsdelivr](https://www.jsdelivr.com/package/npm/tyrell-components).\n\n### Opt-in OKLCH brand layer (new in RC10)\n\nDrop one more `\u003clink\u003e` and rebrand the whole library coherently in light AND dark mode with a single CSS variable:\n\n```html\n\u003c!-- After tyrell.css. Opt-in — load only if you want to retint. --\u003e\n\u003clink rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/tyrell-components@1.0.0-RC10/css/tyrell-brand.css\"\u003e\n\n\u003cstyle\u003e\n  :root {\n    --ty-brand-hue: 200;        /* teal */\n    --ty-brand-chroma: 0.13;\n  }\n\u003c/style\u003e\n```\n\nEvery component — buttons, inputs, dropdowns, calendars, focus rings, scrollbars — retints together. Drag the sliders at [`/docs/theming`](https://gersak.github.io/tyrell/docs/theming) to preview, then copy the `:root` snippet straight to your app.\n\n### Use components anywhere\n\n```html\n\u003cty-button flavor=\"primary\"\u003eClick me\u003c/ty-button\u003e\n\u003cty-dropdown label=\"Country\" placeholder=\"Select...\"\u003e\n  \u003cty-option value=\"us\"\u003eUnited States\u003c/ty-option\u003e\n  \u003cty-option value=\"de\"\u003eGermany\u003c/ty-option\u003e\n\u003c/ty-dropdown\u003e\n```\n\n---\n\n## Using with AI coding agents\n\nTyrell is documented for AI agents from day one. Two artifacts make it work:\n\n- **[Agent instructions snippet](guides/AGENT_INSTRUCTIONS.md)** — 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.\n- **[`llms.txt`](https://gersak.github.io/tyrell/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](https://llmstxt.org) convention.\n\nFor 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.\n\nThe treasure-map entry point for AI navigation is **[guides/AI_GUIDE.md](guides/AI_GUIDE.md)** — two routing tables that get an agent to the right framework guide in one hop.\n\n---\n\n## Guides\n\nPick the entry point for your stack:\n\n### JavaScript / TypeScript\n- **[Vanilla JS Guide](guides/js/JAVASCRIPT_GUIDE.md)** — bundlers, subpath imports, icon tree-shaking, code splitting, SSR\n- **[React Guide](guides/js/REACT_TY_GUIDE.md)** — `tyrell-react` wrappers\n- **[Vue Guide](guides/js/VUE_TY_GUIDE.md)** — Vue 3 / Nuxt native usage (no wrapper package)\n- **[Svelte Guide](guides/js/SVELTE_TY_GUIDE.md)** — Svelte 5 / SvelteKit native usage (no wrapper package)\n\n### ClojureScript\n- **[Quickstart](guides/clj/QUICKSTART.md)** — five-minute setup for any CLJS view layer\n- **[CLJS Substrate Reference](guides/clj/CLOJURESCRIPT_GUIDE.md)** — distribution, shadow-cljs, raw interop, icon tree-shaking\n- **[UIx Guide](guides/clj/UIX_TY_GUIDE.md)** — `defui` + `$`, hooks-only, auto-camelCase props\n- **[Reagent Guide](guides/clj/REAGENT_TY_GUIDE.md)** — hiccup + `r/atom`, `:\u003e` interop with camelCase props\n- **[Helix Guide](guides/clj/HELIX_TY_GUIDE.md)** — `defnc` + `$`, `helix.dom/hooks`, JSX-feeling\n- **[Replicant Guide](guides/clj/REPLICANT_TY_GUIDE.md)** — non-React, raw `\u003cty-*\u003e` elements\n- **[Component Guide](guides/clj/COMPONENT_GUIDE.md)** — `tyrell.shim` for building Web Components in CLJS\n- **[Code Splitting](guides/clj/CODE_SPLITTING.md)** — shadow-cljs lazy loading\n- **[Routing](guides/clj/ROUTING_GUIDE.md)** — `tyrell.router`\n- **[i18n](guides/clj/I18N_GUIDE.md)** — `tyrell.i18n`\n- **[Layout](guides/clj/LAYOUT_GUIDE.md)** — `tyrell.layout` container-aware breakpoints\n\n### Server-driven UIs\n- **[HTMX Guide](guides/js/HTMX_TY_GUIDE.md)** — `hx-*` attributes + form-associated `\u003cty-*\u003e`\n- **[Datastar Guide](guides/DATASTAR_TY_GUIDE.md)** — Datastar + SSE patterns\n\n---\n\n## ClojureScript\n\nAdd to `deps.edn`:\n\n```clojure\n{:deps {dev.gersak/tyrell {:mvn/version \"1.0.0-RC10\"}}}  ; icons come transitively\n```\n\nThat single dep brings:\n- Routing, i18n, layout, icon registry, shim — `tyrell.router`, `tyrell.i18n`, `tyrell.layout`, `tyrell.icons`, `tyrell.shim`\n- The `tyrell.components` shim that side-effect-imports the npm package\n- 12,000+ tree-shakeable icons (`tyrell.lucide`, `tyrell.heroicons.*`, `tyrell.material.*`, `tyrell.fontawesome.*`)\n\nThe npm `tyrell-components` package is declared in this artifact's `deps.cljs`, so shadow-cljs auto-installs it on first build.\n\n### Pick your view layer\n\n| You're using                              | Guide |\n|-------------------------------------------|-------|\n| Reagent, re-frame, UIx, Helix             | [QUICKSTART → Track A](guides/clj/QUICKSTART.md) — `tyrell.react` wrappers |\n| Replicant, vanilla CLJS, server-rendered  | [REPLICANT_TY_GUIDE](guides/clj/REPLICANT_TY_GUIDE.md) — raw `\u003cty-*\u003e` elements |\n\n### Icon registration\n\n`\u003cty-icon name=\"check\"\u003e` is a runtime registry lookup. Register the icons you reference at app startup:\n\n```clojure\n(ns my-app.core\n  (:require [tyrell.components]            ; side-effect: registers all \u003cty-*\u003e elements\n            [tyrell.icons :as icons]\n            [tyrell.lucide :as lucide]\n            [tyrell.heroicons.outline :as ho]))\n\n(defn register-icons! []\n  (icons/register!\n    {:check  lucide/check\n     :search lucide/search\n     :user   ho/user-circle}))\n```\n\nShadow-cljs `:advanced` removes unused icons automatically — you only pay for what you reference. See [CLOJURESCRIPT_GUIDE → Icon registration](guides/clj/CLOJURESCRIPT_GUIDE.md#icon-registration-in-cljs).\n\n### Build Your Own Components\n\nUse `tyrell.shim` to turn any ClojureScript render function into a Web Component:\n\n```clojure\n(ns app.components\n  (:require [replicant.dom :as d]\n            [tyrell.shim :as shim]))\n\n(defn greeting [name]\n  [:div.ty-elevated.p-4.rounded-lg\n   [:h2.ty-text+ \"Hello, \" name \"!\"]\n   [:ty-button {:flavor \"primary\"} \"Wave\"]])\n\n(defn render! [^js el]\n  (d/render (shim/ensure-shadow el)\n    (greeting (or (shim/attr el \"name\") \"World\"))))\n\n(shim/define! \"my-greeting\"\n  {:observed [:name]\n   :connected render!\n   :attr (fn [el _] (render! el))})\n```\n\n```html\n\u003cmy-greeting name=\"Clojure\"\u003e\u003c/my-greeting\u003e\n```\n\n**[Component Building Guide →](guides/clj/COMPONENT_GUIDE.md)** | **[Code Splitting →](guides/clj/CODE_SPLITTING.md)**\n\n---\n\n## Components\n\n| Component | Description |\n|-----------|-------------|\n| `ty-button` | Semantic buttons with flavors, sizes, and icon slots |\n| `ty-input` | Text input with labels, validation, numeric formatting, debounce |\n| `ty-textarea` | Multi-line text with auto-resize and character count |\n| `ty-checkbox` | Styled checkbox with indeterminate state |\n| `ty-switch` | Toggle switch primitive |\n| `ty-radio-group` / `ty-radio` | Exclusive single-choice selection |\n| `ty-dropdown` | Searchable select with keyboard nav and mobile modal |\n| `ty-multiselect` | Multi-select with tags and search |\n| `ty-calendar` | Full calendar with date selection and form integration |\n| `ty-date-picker` | Calendar dropdown for date input |\n| `ty-tabs` / `ty-tab` | Carousel tabs with smooth animations |\n| `ty-wizard` / `ty-step` | Step-by-step wizard with progress tracking |\n| `ty-modal` | Native dialog with backdrop and focus management |\n| `ty-popup` | Anchored popover with smart positioning |\n| `ty-tooltip` | Hover tooltips with placement options |\n| `ty-icon` | SVG icons from Lucide, Heroicons, Material, FontAwesome |\n| `ty-tag` | Removable tags for selections |\n| `ty-copy` | Click-to-copy with visual feedback |\n| `ty-scroll-container` | Scrollable area with fade indicators |\n| `ty-resize-observer` | Self-observing element with debounce |\n\n**[See all components in action →](https://gersak.github.io/tyrell)**\n\n---\n\n## Links\n\n- [Documentation \u0026 Examples](https://gersak.github.io/tyrell)\n- [GitHub](https://github.com/gersak/tyrell)\n- [NPM tyrell-components](https://www.npmjs.com/package/tyrell-components)\n- [NPM tyrell-react](https://www.npmjs.com/package/tyrell-react)\n- [Clojars dev.gersak/tyrell](https://clojars.org/dev.gersak/tyrell)\n- [Clojars dev.gersak/tyrell-icons](https://clojars.org/dev.gersak/tyrell-icons)\n\n---\n\nMIT License\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgersak%2Ftyrell","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgersak%2Ftyrell","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgersak%2Ftyrell/lists"}