Skip to content

RFC 0073 — Standalone usage of @sovereignfs/ui outside the plugin runtime

Status: Implemented
Date: July 2026
Author: External contributor (submitted for consideration; adapted to repository conventions)
Scope: docs/design-system.md. No dependency on @sovereignfs/sdk or any RFC governing plugin composition. No packages/ui code changes — verification confirmed none were needed.
Incorporated into plan: Yes — epic task 9.17.


Summary

Make @sovereignfs/ui usable as an ordinary npm dependency in an external app that is not a Sovereign plugin and does not run inside the Sovereign runtime shell — with its design tokens, components, and hooks all working correctly without any runtime-injected globals. Most of the technical groundwork already exists (see Current state); this RFC is mainly about stating and documenting a guarantee that today is true by accident, not by contract.

Motivation

@sovereignfs/ui is a well-scoped, accessibility-conscious component library (Button, FormField, TagInput, StatusBadge, Icon, mobile interaction hooks, etc.) that's a good fit for apps well beyond Sovereign plugins. Today the documented usage pattern assumes the component tree is mounted inside the Sovereign runtime shell, which injects the --sv-* design token stylesheet globally. There is no stated compatibility guarantee for a standalone consumer, and no explicit confirmation that components/hooks (e.g. useIsMobile, useLongPress) have no hidden dependency on runtime-provided context.

This matters directly for a separate standalone app under active development that wants visual consistency with the Sovereign ecosystem for its own admin/curator-facing interface, without becoming a plugin itself.

Current state (what this builds on)

The package is closer to standalone-ready than the original draft assumed — this RFC corrects that and scopes the remaining gap precisely:

  • packages/ui/package.json is already published-shaped: not private, publishConfig.access: "public", version 0.41.0, and exports already declares a standalone tokens entry point ("./tokens.css": "./src/tokens.css", plus ./tokens/primitives.css and ./tokens/semantic.css). The original draft's premise ("packages/ui is listed as yet to be published") is stale — confirming current npm publication status (has a version actually been published to the registry, distinct from being publish-configured) is the one open item here, not building the export.
  • grep -rn "@sovereignfs/sdk" packages/ui/src returns no matches — the package already has zero coupling to the SDK or plugin contract, which the draft flagged as something "worth flagging in review." It's already satisfied.
  • packages/ui/src/hooks/ (useIsMobile.ts, useLongPress.ts, useDoubleTap.ts, useCommitOnEnterOrBlur.ts) contain no createContext/Provider dependency — they're self-contained. The only Provider/createContext usage in the package is local to Toast and Dialog (own internal state, not a runtime-injected global), per grep -rln "createContext\|Provider" packages/ui/src. No SovereignUIRoot-equivalent wrapper exists or is needed today.
  • Dark mode is driven by a [data-theme='dark'] attribute selector in packages/ui/src/tokens/semantic.css:91, set at :root — not a prefers-color-scheme media query and not JS-context-dependent. An external app needs only to toggle that attribute itself; this is not currently documented anywhere outside the CSS source comment (packages/ui/src/tokens/semantic.css:6).
  • docs/design-system.md has no "standalone usage" section — confirmed by search; the closest existing precedent for a tiered stability statement is docs/sdk-stability.md, which this RFC proposes mirroring rather than inventing a new format.

Non-goals

  • Changing the plugin-facing usage pattern, which works today and stays as-is.
  • Theming/rebrand support beyond exposing the existing token set — a separate, larger conversation.
  • Any @sovereignfs/sdk dependency, direct or transitive. The motivating consumer wants the component library and design tokens only — no session access, no plugin manifest, no runtime composition.

Proposed design

1. Confirm and state npm publication status

Confirm whether a version of @sovereignfs/ui has actually been published to the npm registry (publish-configured is not the same as published). State this plainly in docs/design-system.md so external consumers aren't guessing.

2. State the "no root provider required" guarantee explicitly

Per Current state, no context provider is required today. Rather than leaving this implicit, add an explicit statement to docs/design-system.md: components are pure CSS-variable/props consumers; no wrapper is required to use them outside the runtime shell. If a future component needs shared context (theme, density, locale), that becomes a breaking addition subject to the semver policy below — not a silent assumption.

3. State hooks are runtime-independent

Add an explicit compatibility guarantee for useIsMobile, useLongPress, useDoubleTapHandler, useCommitOnEnterOrBlur: "these hooks have no dependency on the Sovereign runtime and are safe to use in any React 18+ app" (per Current state, this is already true — the gap is only that it's undocumented).

4. Add a "standalone usage" section to design-system.md

A short, explicit section covering:

  • Installation (npm install @sovereignfs/ui)
  • Importing tokens (import '@sovereignfs/ui/tokens.css' — already a valid import path per the existing exports map)
  • No required root wrapper (per §2)
  • Dark mode toggling outside the runtime shell: set data-theme="dark" on the consumer's own :root (or documentElement), matching [data-theme='dark'] in packages/ui/src/tokens/semantic.css:91
  • A minimal working example (a form using FormField + Input)

5. Tiered stability statement for the standalone surface

docs/sdk-stability.md sets a precedent for a tiered stability statement. Mirror it for @sovereignfs/ui's standalone consumption surface: token names and core primitives (Button, FormField, Input, Card, tokens) are stable; editor-workflow primitives added for plugin-internal use (e.g. SplitPane, per epic task 9.16) may be marked experimental for standalone consumers if they carry assumptions not yet audited outside a plugin context.

Security considerations

None expected — this is a pure client-side styling/component surface with no auth or data implications. Worth confirming during implementation that no component silently assumes a same-origin runtime API (e.g. an icon-loading endpoint) that wouldn't resolve correctly from an external domain — confirmed during implementation via grep across packages/ui/src for fetch(/new URL(/src="/…"-style paths (zero matches); see the "No same-origin or runtime-relative asset dependencies" subsection this RFC added to docs/design-system.md.

Alternatives considered

  • Fork or vendor the token set into the external app instead of depending on the package directly. Rejected as a first choice — it immediately drifts from the source of truth and defeats the purpose of visual consistency across the ecosystem. A fallback only if the package genuinely can't be used standalone (Current state suggests it already can).

Open questions

  • Are there icon assets served from a Sovereign-runtime-relative path that wouldn't resolve for an external consumer? Resolved: no. Verified against the actual source (grep across packages/ui/src for fetch(, new URL(, and src="/…"-style paths — zero matches). Icons are bundled as inline SVG React components at build time.
  • Should the tiered stability statement live entirely in docs/design-system.md, or get its own docs/ui-stability.md?Resolved: kept as a section in docs/design-system.md, per the recommendation — no separate doc needed yet.

Adoption path

Implemented in epic task 9.17 as a single documentation-only PR — no packages/ui code changes; verification confirmed none were needed. See the new "Standalone usage" section in docs/design-system.md.

Changelog

VersionDateChange
0.1July 2026Initial draft
0.2July 2026Implemented. Added the "Standalone usage" section to docs/design-system.md; resolved both open questions; confirmed npm publication status.

Open source under AGPL-3.0. Each Sovereign instance is independently operated.