{"id":28403426,"url":"https://github.com/soybeanjs/soybean-ui","last_synced_at":"2026-05-17T09:02:40.137Z","repository":{"id":283962705,"uuid":"580398209","full_name":"soybeanjs/soybean-ui","owner":"soybeanjs","description":"A powerful and elegant Vue 3 component system with headless primitives and ready-to-use styled wrappers.","archived":false,"fork":false,"pushed_at":"2026-05-10T07:13:34.000Z","size":13673,"stargazers_count":174,"open_issues_count":15,"forks_count":14,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-05-10T07:31:07.203Z","etag":null,"topics":["radix-vue","shadcn-ui","uikit","unocss","vue3"],"latest_commit_sha":null,"homepage":"https://ui.soybeanjs.cn","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/soybeanjs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2022-12-20T13:14:46.000Z","updated_at":"2026-05-10T06:02:55.000Z","dependencies_parsed_at":"2026-02-01T16:01:22.876Z","dependency_job_id":"8a6f6fb5-d1db-46d5-9eae-81d50273f3bb","html_url":"https://github.com/soybeanjs/soybean-ui","commit_stats":null,"previous_names":["soybeanjs/soybean-ui"],"tags_count":148,"template":false,"template_full_name":null,"purl":"pkg:github/soybeanjs/soybean-ui","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soybeanjs%2Fsoybean-ui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soybeanjs%2Fsoybean-ui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soybeanjs%2Fsoybean-ui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soybeanjs%2Fsoybean-ui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/soybeanjs","download_url":"https://codeload.github.com/soybeanjs/soybean-ui/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soybeanjs%2Fsoybean-ui/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33130240,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-17T06:27:06.342Z","status":"ssl_error","status_checked_at":"2026-05-17T06:26:59.432Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["radix-vue","shadcn-ui","uikit","unocss","vue3"],"created_at":"2025-06-01T17:36:50.655Z","updated_at":"2026-05-17T09:02:40.130Z","avatar_url":"https://github.com/soybeanjs.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/soybeanjs/soybean-ui\"\u003e\n    \u003cimg src=\"./public/logo.svg\" alt=\"Logo\" width=\"150\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n# SoybeanUI\n\nEnglish | [中文](./README.zh-CN.md)\n\n[![license](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE)\n[![github stars](https://img.shields.io/github/stars/soybeanjs/soybean-ui)](https://github.com/soybeanjs/soybean-ui)\n\nSoybeanUI is an elegant, modern, accessible and high-quality UI component library with shadcn-like design for Vue 3, built on top of a robust headless foundation. It provides a comprehensive set of accessible, customizable, and performant components.\n\n## 📚 Architecture\n\nSoybeanUI is built on a strict **two-layer separation** model:\n\n```\n┌─────────────────────────────────────────┐\n│           @soybeanjs/ui (src/)          │\n│  S-prefixed components   (SButton…)     │\n│  UnoCSS classes · tailwind-variants     │\n│  provideXUi(ui)  ──────────────────┐    │\n└────────────────────────────────────┼────┘\n                                     │ style injection\n┌────────────────────────────────────▼────┐\n│        @soybeanjs/headless (headless/)  │\n│  Logic · State · A11y · Keyboard nav    │\n│  useUiContext() reads injected classes  │\n│  Zero styles — works with any CSS       │\n└─────────────────────────────────────────┘\n```\n\n### Packages\n\n| Package                 | Role                              | Components                        |\n| ----------------------- | --------------------------------- | --------------------------------- |\n| **@soybeanjs/headless** | Logic, state, a11y. Zero styles.  | 95 component dirs, 25 composables |\n| **@soybeanjs/ui**       | Styled wrappers. UnoCSS + `tv()`. | 91 `S`-prefixed components        |\n\n**Data flow is strictly one-way**: `headless` → `src`. The styled layer never imports from headless's internals — it injects style tokens via `provideXUi(computedUi)` which headless components read through `useUiContext()`.\n\nSome multi-slot headless components also expose `Compact` aggregators, such as `AccordionCompact` and `TableCompact`. They keep item iteration and default content/icon composition inside headless, while the UI layer stays focused on styling and prop forwarding.\n\nCurrent Compact-style coverage also includes flows such as card, date-field, dialog, editable, hover-card, layout, navigation-menu, pagination, popover, and stepper, when those structures are stable enough to live in headless.\n\n### Style Injection\n\nEvery multi-slot headless component exposes a `provide{Name}Ui` function. The styled wrapper computes classes using `tailwind-variants` and injects them:\n\n```ts\n// In the styled wrapper (src/)\nconst ui = computed(() =\u003e\n  mergeVariants(\n    accordionVariants({ size: props.size }), // tv() output\n    props.ui, // user overrides\n    { root: props.class } // class prop\n  )\n);\nprovideAccordionUi(ui); // headless reads this via useAccordionUi()\n```\n\n### Theme System\n\n- **`ThemeColor`** — 8 semantic colors: `primary` · `destructive` · `success` · `warning` · `info` · `carbon` · `secondary` · `accent`\n- **`ThemeSize`** — 6 sizes: `xs` · `sm` · `md` · `lg` · `xl` · `2xl` (base 16px at `md`)\n- **`ConfigProvider`** — sets global `dir`, `locale`, `nonce`, and default `tooltip` config for the entire component tree, including RTL layout switching\n- **`cn()`** — Tailwind-aware class merge (`clsx` + `tailwind-merge`), used for conflict-free class composition\n\n### Locale Support\n\n`ConfigProvider` supports the following locale bundles:\n\n| Code    | Language            |\n| ------- | ------------------- |\n| `zh-CN` | Simplified Chinese  |\n| `zh-TW` | Traditional Chinese |\n| `en`    | English             |\n| `ar`    | Arabic              |\n| `ja`    | Japanese            |\n| `ko`    | Korean              |\n| `de`    | German              |\n| `fr`    | French              |\n| `es`    | Spanish             |\n| `pt-BR` | Portuguese (Brazil) |\n| `ru`    | Russian             |\n| `tr`    | Turkish             |\n| `id`    | Indonesian          |\n\nOnly `en` and `zh-CN` are pre-registered by default. `registerLocale` supports two registration styles:\n\n- Pass a `LocaleRegistry` object. Built-in locale files from `@soybeanjs/headless/locale/{code}` already export this shape, including `dir` metadata.\n- Pass a locale key plus `LocaleMessages` for a lightweight custom locale.\n\nThe shorthand `registerLocale(key, messages)` form uses the key as the locale name and falls back to `ltr`. Use the object form when you need explicit metadata such as `rtl`.\n\n```ts\nimport { en, registerLocale } from '@soybeanjs/headless/locale';\nimport type { LocaleMessages } from '@soybeanjs/headless/locale';\nimport ar from '@soybeanjs/headless/locale/ar';\n\nregisterLocale(ar);\n\nconst customMessages: LocaleMessages = {\n  ...en.messages,\n  pagination: {\n    ...en.messages.pagination,\n    nextPage: 'Next →',\n    prevPage: '← Prev'\n  }\n};\n\nregisterLocale('custom', customMessages);\n```\n\n### Package Exports\n\n**@soybeanjs/headless** ships fine-grained sub-paths:\n\n```ts\nimport { AccordionRoot } from '@soybeanjs/headless'; // all components\nimport { useControllableState } from '@soybeanjs/headless/composables'; // 25 composables\nimport { transformPropsToContext } from '@soybeanjs/headless/shared'; // pure TS utils\nimport { createMonth } from '@soybeanjs/headless/date'; // shared date helpers\nimport * as Headless from '@soybeanjs/headless/namespaced'; // namespace object\nimport type { AccordionUiSlot } from '@soybeanjs/headless/accordion'; // per-component\nimport type { UiClass } from '@soybeanjs/headless/types'; // shared type surface\n```\n\n**@soybeanjs/ui** exports:\n\n```ts\nimport { SButton, SAccordion } from '@soybeanjs/ui'; // all components\nimport '@soybeanjs/ui/styles.css'; // pre-built UnoCSS stylesheet\n// Also: @soybeanjs/ui/nuxt · @soybeanjs/ui/resolver\n```\n\n## 🛠 Development Workflow\n\nIf you contribute new public components, exports, or API descriptions, keep generated surfaces in sync through the official scripts instead of editing generated files by hand.\n\n```bash\npnpm sui headless                 # sync headless component names and namespaced exports\npnpm sui ui                       # sync ui component names\npnpm sui api                      # regenerate docs api json and locale baseline data\npnpm sui api-locales              # refresh api locale template data only\npnpm sui changelog                # regenerate docs changelog json and locale baseline data\npnpm sui api-translate -- --locale zh-CN\npnpm sui changelog-translate -- --locale zh-CN\n```\n\nThe docs site now renders component docs through `UsageCode`, `PlaygroundGallery`, and `ComponentApi`. Component detail pages and `/releases` also read generated changelog data from `docs/src/generated/changelog/` and `docs/src/generated/changelog-locales/`.\n\nPublic API or demo delivery changes should keep docs, playground examples, and generated API data aligned. Changelog mapping, release presentation, and changelog locale template changes should keep generated changelog data aligned as well.\n\n## 📦 Installation\n\n### Using the Styled UI Library (Recommended)\n\nIf you want ready-to-use components with a modern design:\n\n```bash\npnpm add @soybeanjs/ui\n```\n\n### Using the Headless Library\n\nIf you want to build your own design system from scratch:\n\n```bash\npnpm add @soybeanjs/headless\n```\n\n## 🚀 Usage\n\n### @soybeanjs/ui\n\n1. **Import Styles**\n\n   Import the CSS file in your main entry file (e.g., `main.ts`):\n\n```ts\nimport '@soybeanjs/ui/styles.css';\n```\n\n2. **Global Registration (Optional)**\n\n   You can register components globally or import them on demand.\n\n3. **On-demand Import (Recommended)**\n\n   We recommend using `unplugin-vue-components` for auto-importing components.\n\n```ts\n// vite.config.ts\nimport Components from 'unplugin-vue-components/vite';\nimport UiResolver from '@soybeanjs/ui/resolver';\n\nexport default defineConfig({\n  plugins: [\n    Components({\n      resolvers: [UiResolver()]\n    })\n  ]\n});\n```\n\n4. **Nuxt Module**\n\n```ts\n// nuxt.config.ts\nexport default defineNuxtConfig({\n  modules: ['@soybeanjs/ui/nuxt']\n});\n```\n\n### @soybeanjs/headless\n\nThe headless components provide the functionality without the styles.\n\nFor data-driven multi-slot patterns, prefer the exported `Compact` variant when it exists. It is the headless entry point for opinionated composition, while the regular parts remain available for fully manual assembly.\n\n```vue\n\u003cscript setup\u003e\nimport { AccordionRoot, AccordionItem, AccordionTrigger, AccordionContent } from '@soybeanjs/headless';\n\u003c/script\u003e\n\n\u003ctemplate\u003e\n  \u003cAccordionRoot\u003e\n    \u003cAccordionItem value=\"item-1\"\u003e\n      \u003cAccordionTrigger\u003eIs it accessible?\u003c/AccordionTrigger\u003e\n      \u003cAccordionContent\u003eYes. It adheres to the WAI-ARIA design pattern.\u003c/AccordionContent\u003e\n    \u003c/AccordionItem\u003e\n  \u003c/AccordionRoot\u003e\n\u003c/template\u003e\n```\n\n## ✨ Features\n\n- **Accessible**: Follows WAI-ARIA patterns for roles, focus management, and keyboard navigation.\n- **RTL ready**: Switch supported components between LTR and RTL layouts with `ConfigProvider`.\n- **Headless-first**: Logic and styles are fully separated — use `@soybeanjs/headless` alone to build any design system.\n- **Type Safe**: Written in strict TypeScript. All props, emits, slots, and context values are typed.\n- **Customizable at every level**: Override individual slot classes via the `ui` prop, or swap the entire style layer.\n- **Lightweight \u0026 Tree-shakable**: Import only the components you use. Each component is individually tree-shakable.\n- **Nuxt ready**: First-class Nuxt module with auto-registration (`@soybeanjs/ui/nuxt`).\n- **unplugin support**: Auto-import resolver for `unplugin-vue-components` (`@soybeanjs/ui/resolver`).\n\n## 💝 Credits\n\n- [reka-ui](https://github.com/unovue/reka-ui)\n- [oku-ui](https://github.com/oku-ui/primitives)\n- [shadcn-vue](https://github.com/unovue/shadcn-vue)\n- [shadcn/ui](https://github.com/shadcn/ui)\n- [nuxt-ui](https://github.com/nuxt/ui)\n- [unocss](https://github.com/unocss/unocss)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoybeanjs%2Fsoybean-ui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsoybeanjs%2Fsoybean-ui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoybeanjs%2Fsoybean-ui/lists"}