Summary
Add @appica/ui-svelte as a sibling package to @appica/ui-react in this monorepo: same design tokens and public component set, implemented in Svelte 5 (runes) instead of React.
CONTRIBUTING.md already treats extra framework packages as expected (pnpm dev "as more packages land"), but the documented workflow, playground, and repo layout are still React-only. This issue is the discussion point before any implementation PR, per the contributing guide.
Motivation
- The root
AGENTS.md / monorepo layout already describe packages/svelte as the next integration after React.
- Svelte 5 apps cannot consume
@appica/ui-react without a React runtime. A first-party port keeps one visual language across frameworks.
- Tokens, variants, and accessibility expectations should stay aligned with React so docs and Figma remain a single source of truth.
Proposed stack
| Concern |
React today |
Svelte proposal |
| Framework |
React 19 |
Svelte ^5.33 (runes only) |
| Headless primitives |
Base UI (@base-ui/react) |
Native HTML in Wave 1; bits-ui in Wave 2 |
| Motion |
Motion |
CSS + svelte/transition (no Motion) |
| Styling |
Tailwind v4 + CSS variables |
Same tokens (var(--color-…), var(--radius-…), var(--transition-…)) |
| Tests |
vitest + Testing Library + vitest-axe |
Same, with @testing-library/svelte |
| Playground |
pnpm playground → playgrounds/react |
pnpm playground:svelte → playgrounds/svelte |
Do not add bits-ui until a component needs a headless primitive. Polymorphism is href / el (no public child snippet, no React render / cloneElement).
Scope
Port every public @appica/ui-react export (components, hooks, providers, color lib). Track progress in packages/svelte/COMPONENT-STATUS.md.
Wave 1 (native HTML): presentational primitives such as Alert, Avatar, Badge, ButtonGroup, Card, Input, Textarea, Table, Tabs chrome that does not need a primitive, ThemeProvider, and related hooks.
Wave 2 (bits-ui or custom): overlays and form controls that React wraps with Base UI: Accordion, Dialog, Select, Combobox, DateField / DatePicker / TimeField / Calendar, Menu family, Slider, Toast, and so on. Color controls and Carousel have no bits-ui analog and stay custom (Embla for Carousel, same plugins as React).
Svelte-specific API notes to keep in the port (not 1:1 React copies):
$props() / $bindable() for fields; snippets (children, start, end) instead of slots.
createContext / setContext instead of cloneElement.
- Overlay triggers take
class={buttonVariants(...)} directly; links that look like a button use buttonVariants on <a>, not href on Button.
- Date values stay
@internationalized/date DateValue / TimeValue, not native Date.
src/index.ts and the package.json exports map are generated (pnpm --filter @appica/ui-svelte sync-exports).
Docs and contributing workflow
When the package lands, update the contributor-facing docs that today only mention React:
- CONTRIBUTING.md: Node floor (repo
engines is >=22), pnpm --filter @appica/ui-svelte …, pnpm playground:svelte, playgrounds/svelte/src/app.svelte as the Svelte scratch page, and a packages/svelte layout paragraph pointing at packages/svelte/AGENTS.md.
- Root
README.md: add @appica/ui-svelte to the package table once it is published.
- Root scripts:
pack:svelte (and release if Svelte should publish with the same flow).
Docs site work (appica.dev /ui) lives in the separate appica-dev repo and is out of scope here, other than packing the tarball (pnpm pack:svelte) so that site can consume it.
Acceptance criteria
Out of scope
- Vue / HTML packages.
- Changing the React public API to match Svelte.
- appica.dev docs pages (separate repo), aside from making the packed tarball consumable.
Summary
Add
@appica/ui-svelteas a sibling package to@appica/ui-reactin this monorepo: same design tokens and public component set, implemented in Svelte 5 (runes) instead of React.CONTRIBUTING.mdalready treats extra framework packages as expected (pnpm dev"as more packages land"), but the documented workflow, playground, and repo layout are still React-only. This issue is the discussion point before any implementation PR, per the contributing guide.Motivation
AGENTS.md/ monorepo layout already describepackages/svelteas the next integration after React.@appica/ui-reactwithout a React runtime. A first-party port keeps one visual language across frameworks.Proposed stack
^5.33(runes only)@base-ui/react)svelte/transition(no Motion)var(--color-…),var(--radius-…),var(--transition-…))@testing-library/sveltepnpm playground→playgrounds/reactpnpm playground:svelte→playgrounds/svelteDo not add bits-ui until a component needs a headless primitive. Polymorphism is
href/el(no publicchildsnippet, no Reactrender/cloneElement).Scope
Port every public
@appica/ui-reactexport (components, hooks, providers,colorlib). Track progress inpackages/svelte/COMPONENT-STATUS.md.Wave 1 (native HTML): presentational primitives such as Alert, Avatar, Badge, ButtonGroup, Card, Input, Textarea, Table, Tabs chrome that does not need a primitive, ThemeProvider, and related hooks.
Wave 2 (bits-ui or custom): overlays and form controls that React wraps with Base UI: Accordion, Dialog, Select, Combobox, DateField / DatePicker / TimeField / Calendar, Menu family, Slider, Toast, and so on. Color controls and Carousel have no bits-ui analog and stay custom (Embla for Carousel, same plugins as React).
Svelte-specific API notes to keep in the port (not 1:1 React copies):
$props()/$bindable()for fields; snippets (children,start,end) instead of slots.createContext/setContextinstead ofcloneElement.class={buttonVariants(...)}directly; links that look like a button usebuttonVariantson<a>, nothrefonButton.@internationalized/dateDateValue/TimeValue, not nativeDate.src/index.tsand the package.jsonexportsmap are generated (pnpm --filter @appica/ui-svelte sync-exports).Docs and contributing workflow
When the package lands, update the contributor-facing docs that today only mention React:
enginesis>=22),pnpm --filter @appica/ui-svelte …,pnpm playground:svelte,playgrounds/svelte/src/app.svelteas the Svelte scratch page, and apackages/sveltelayout paragraph pointing atpackages/svelte/AGENTS.md.README.md: add@appica/ui-svelteto the package table once it is published.pack:svelte(andreleaseif Svelte should publish with the same flow).Docs site work (appica.dev
/ui) lives in the separateappica-devrepo and is out of scope here, other than packing the tarball (pnpm pack:svelte) so that site can consume it.Acceptance criteria
packages/sveltepublishes@appica/ui-sveltewith the same component coverage as@appica/ui-react(checklist inCOMPONENT-STATUS.md).pnpm --filter @appica/ui-svelte test.pnpm --filter @appica/ui-svelte typecheckandbuildsucceed; build emits.js+.d.ts(+.svelte) for each public export.playgrounds/sveltehot-reloads against library source (pnpm playground:svelte).CONTRIBUTING.mdand root README document the Svelte package the same way they document React.@defaultwhen there is a default, American English, hyphen not a typographic dash).Out of scope