@mbsw/ui
v1.3.0
Published
<p> <a href="https://mbsw.io/docs/"> <img src="https://mbsw.io/docs/brand/logo-en-light.svg" alt="MBSW" height="40" /> </a> </p>
Readme
mbsw/ui
Build React interfaces with MBSW components, shared design tokens, and light and dark themes. Install the package, load its styles, and compose components in your application.
Quick start · Components · Styling · Composition · Troubleshooting · Versioning · Resources
What you get
- Ready-to-use React components for forms, navigation, dates, overlays, and feedback.
- Consistent styling through
@mbsw/tokens, including light and dark themes. - Radix-based interaction primitives and component-specific composition APIs.
- Precompiled component CSS: no source-code copying or Tailwind scanning of the package is needed.
MBSW provides building blocks. Your application owns data, routing, permissions, theme preferences, and how those blocks work together.
Installation
Use MBSW UI in a React 19 application.
npm install @mbsw/ui @mbsw/tokens tailwindcss@^4| Peer dependency | Supported version |
| --------------- | ----------------- |
| react | ^19.0.0 |
| react-dom | ^19.0.0 |
| @mbsw/tokens | ^1.0.0 |
Upgrading from 0.x? Install both @mbsw/ui@^1.0.0 and @mbsw/tokens@^1.0.0 together. The 1.0.0 release retains the runtime, styles, and public API of UI 0.19.1 and tokens 0.6.1; the UI package now requires tokens 1.x.
The command includes Tailwind CSS v4 to satisfy the tokens package's peer dependency. Component CSS is already compiled, so you do not need a Tailwind build step unless your application uses Tailwind utilities.
Managed Radix interaction patch
Installing @mbsw/ui does not install or propagate MBSW's application-root Radix patch. The patch is not required for every npm consumer, but managed applications that require the same overlay interaction behavior as MBSW's patched environment must apply it explicitly.
The temporary patch targets only @radix-ui/[email protected]. It closes listener-registration gaps where the first outside pointerdown can be missed or an early Escape can reach a lower layer. It does not change layer priority, cancellation policy, public APIs, or z-index. Both ESM and CommonJS entrypoints are patched while retaining a single shared module per build.
| Patch identity | Expected value |
| ---------------------- | ------------------------------------------------------------------ |
| Dependency | @radix-ui/[email protected] |
| SHA-256 of patch bytes | 4350a62ebc0e84d26732886828e9ad28b9b75852f73b2a8ac23c00f8ff3e0f9a |
Managed applications obtain the approved patch file from their MBSW maintainer, apply those exact bytes using their own pnpm.patchedDependencies, and commit the matching lockfile. Verify the resolved dependency version and patch hash in that application; the UI package version alone does not prove that the patch is installed. Do not bundle a second copy of the primitive or use a runtime monkey-patch to reproduce this setup.
| Validation environment | What its result establishes | | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Unpatched npm consumer | The published package's installation, public API, styles, and the interactions actually exercised in that environment. It does not establish parity with the managed registration-lifetime fix. | | Managed patched application | The exact patch identity plus that application's tested interactions. Test pointerdown, Escape, focus return, nested overlays, and cancellation in the application's real compositions; MBSW's own regression results do not replace these checks. |
Release and adoption results must identify which environment was checked. Remove the patch only after an upstream unpatched version passes the relevant interaction regressions and every managed consumer has migrated; remove the application-root patch configuration and lockfile reference together.
Quick start
1. Load the styles
Add these imports to your application's global stylesheet, in this order:
@import '@mbsw/tokens/styles.css';
@import '@mbsw/tokens/motion.css';
@import '@mbsw/ui/styles.css';Load this stylesheet once in your application entry point. In frameworks with a root layout or global CSS entry, load it there. Component styles and animation utilities are already compiled; you do not need to scan node_modules/@mbsw/ui with Tailwind.
The UI stylesheet also provides Foundation Icon size defaults. Load it when using Icon, including standalone icons. Sizes follow the token scale, while your className and inline style can override width and height.
The motion stylesheet applies a global reduced-motion override. It shortens animations and transitions when the user has requested reduced motion.
Component animation utilities are compiled from the pinned Tailwind build dependency into @mbsw/ui/styles.css. Consumers do not install Tailwind to compile these prebuilt component styles; the tokens package's declared Tailwind peer dependency still applies.
Within MBSW, an owned @keyframes implementation is used only when needed for parity, accessibility, performance, or bounded package CSS. This implementation rule does not restrict your application's custom animations.
2. Render a component
import { Button } from '@mbsw/ui';
export function SaveButton() {
return (
<Button tone="primary" variant="solid">
Save changes
</Button>
);
}Components are available from the package root. Use named imports for the components you need. No MBSW-specific provider is required for this Button example; more complex components may require their own root and child structure.
Components
A selection of the available components:
| Category | Components | | ----------------------- | ----------------------------------------------------------- | | Actions and input | Button, Input, Textarea, InlineEdit, Select, Toggle, Slider | | Dates | Calendar, DatePicker | | Layout and content | Card, ScrollArea, Inspector, MediaSlot, BoardCard, Composer | | Navigation and identity | Breadcrumb, Tabs, Avatar | | Overlays and feedback | Dialog, Popover, DropdownMenu, Tooltip, HoverCard, Toast | | Progress | Progress, ProgressRing, Spinner |
Progress and ProgressRing are separate components. Choose the component whose presentation and interaction contract matches your screen.
Explore Documentation for component examples and guides. Its deployed version may differ from your installation; your installed package's TypeScript declarations are the reference for available exports and props.
Styling
Optional Tailwind integration
If your application uses Tailwind CSS v4, load Tailwind first and include the MBSW theme extension:
@import 'tailwindcss';
@import '@mbsw/tokens/styles.css';
@import '@mbsw/tokens/tailwind.css';
@import '@mbsw/tokens/motion.css';
@import '@mbsw/ui/styles.css';This makes MBSW token aliases available to your application's Tailwind utilities. The application owns the build integration and Preflight reset.
Light and dark themes
The token stylesheet supplies the default light theme. Add dark to the document root to switch to dark tokens:
<html class="dark">
<!-- Application -->
</html>Remove the class to return to the light theme. Your application owns the theme preference and persistence.
Extend supported component roots
Use public className, style, and native props where the component supports them.
import { Button } from '@mbsw/ui';
<Button className="w-full" data-testid="save-button">
Save changes
</Button>;MBSW styles provide the defaults. Keep accessible names, keyboard behavior, and component anatomy intact when extending them.
Stylesheet entry points
| Import | Purpose |
| --------------------- | ------------------------------------------------------------------------------------------- |
| @mbsw/ui/styles.css | All component styles, including compiled animation utilities. Recommended for applications. |
| @mbsw/ui/chart.css | Chart presentation styles for a selective setup. |
| @mbsw/ui/button.css | Retained compatibility-only export. Use the aggregate stylesheet for new integrations. |
Foundation styles come from @mbsw/tokens; load them before the UI stylesheet.
Composition
Use a custom semantic element
Components that support asChild can use your element as their root. For example, render a link with Button styling:
import { Button } from '@mbsw/ui';
<Button asChild>
<a href="/settings">Open settings</a>
</Button>;Pass one concrete element. Custom components must forward the received props and ref to their rendered element. The child determines the element type and must match any ref you provide.
asChild support is component-specific, not universal. For Button, disabled and convenience icon props belong to the native-button form, not the asChild form.
Keep semantics explicit
- Give icon-only buttons an accessible name with
aria-label. - Associate form controls with labels and provide meaningful descriptions for errors.
- Use HoverCard for read-only supporting content; use Popover for interactive content.
- Follow each component's declared slots and child structure.
- Keep product-specific state, routing, permissions, and custom overlay composition in the application.
MBSW owns component defaults and supported interaction contracts. The application owns the behavior introduced by its custom composition.
Compose agent profiles
The working-state, agent badge content and mixed-group composition APIs below are available starting with @mbsw/[email protected].
Use AgentAvatar for shared avatar presentation. Your application owns profile images, runtime/color selection, data, and any domain-specific profile component; MBSW does not bundle an AgentProfile or product image collection.
<AgentAvatar
type="image"
src={profileImageUrl}
label={profileName}
isWorking={isWorking}
workingLabel={localizedWorkingText}
/>Provide a non-empty workingLabel while working. The external ring respects reduced motion and remains separate from disabled image styling. Its visual positioning uses CSS anchor positioning, including anchor-scope; use a browser that supports these features. MBSW does not install a positioning polyfill. Profile, working and error descriptions remain accessible through the component's naming and description relationships.
To move or scale the complete working avatar, apply transform to an application-owned wrapper containing AgentAvatar. Root className and style still target the painted avatar itself; a transform on that root does not consistently move its external ring across browsers.
Agent AvatarBadge supports default, image and error content through avatarType; connection status remains independent of the profile content. AvatarGroupCount sizes human avatars and agent badges consistently and accepts wrapMember for application-owned, read-only Tooltip or HoverCard composition. When wrapping an error member, retain its existing focus stop rather than adding another focusable wrapper.
Group children must be human Avatar or agent AvatarBadge elements, not human or runtime badges. For typed createElement children, retain the agent props rather than its widened AvatarBadgeProps union:
import { createElement } from 'react';
import { AvatarBadge, type AvatarBadgeProps } from '@mbsw/ui';
const agentMember = createElement<Extract<AvatarBadgeProps, { type: 'agent' }>>(
AvatarBadge,
{ type: 'agent', label: 'Agent', statusLabel: 'Online' },
);The new mixed-group API rejects concrete human/runtime badge props and direct AgentAvatarProps; agent group members use AvatarBadge with type="agent". React JSX and structurally narrowed element props can erase component identity, so the group also checks component identity and agent type at runtime. TypeScript alone does not validate every child, even when a props-only ReactElement annotation is present.
Localize component text
The following localization APIs are available starting with @mbsw/[email protected].
Applications supply translated text; MBSW does not require an application i18n library.
Calendaracceptslabels?: Partial<CalendarLabels>for view tabs, navigation, weekday names, month/year formatting and accessible announcements. Omitted fields retainCALENDAR_DEFAULT_LABELS(Korean). Pass every field when you want a fully translated calendar; choosingCALENDAR_LOCALES.enforlabels.localealone only translates react-day-picker's date names and announcements.DatePickerContentaccepts the same bundle throughcalendarProps.labels. The application still owns the trigger and popup's accessible name.InlineEditacceptseditLabel,cancelLabelandclearLabel.clearLabelnames the single-line editor's internal clear-value button, independently from cancel. The default InlineEdit stylesheet keeps that button hidden; this prop also supports consumers that already reveal it through their custom styles.
formatMonth and formatMonthName receive UTC date-only Date values, just like
Calendar's other date props and callbacks. Use UTC getters or an explicit
timeZone: 'UTC' when formatting. weekdays contains seven names in Sunday-first
order. Localization keeps the Gregorian calendar, Sunday start, panel geometry
and selection/keyboard behavior unchanged. Use compact translated titles that fit
the existing panel; applications own handling for longer custom titles.
Keep translation lookup in your application and pass the resulting text through the component APIs above. For example:
<InlineEdit
editLabel="Edit title"
cancelLabel="Cancel editing"
clearLabel="Clear title"
/>Troubleshooting
| If you see… | Check… |
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| Unstyled components or missing colors | Load the global stylesheet, with token styles before UI styles. |
| Missing Tailwind utility classes in your own markup | Configure Tailwind v4 in your application and include the optional theme extension. Precompiled UI CSS does not generate application utilities. |
| A theme that does not change | Toggle dark on the document root, and avoid fixed colors that override semantic tokens. |
| A documentation example that does not type-check | Compare the example with your installed version's public types and peer dependency ranges before upgrading. |
| Unexpected behavior in custom compositions | Check the component's supported slots, native semantics, accessible names, and prop/ref forwarding. |
Versioning
MBSW uses Semantic Versioning 2.0.0 as its baseline. Compatible fixes use patch releases, compatible additions use minor releases, and breaking changes require a major release.
Under MBSW's product policy, a major version may also mark an explicitly announced product milestone, including the transition to a stable 1.0.0 API. A major version does not by itself mean that breaking changes occurred. Release notes explain the reason for the version change, any compatibility changes, and whether migration steps are needed.
@mbsw/ui and @mbsw/tokens are versioned independently. Check the UI package's peer dependency range when upgrading.
Resources
- Documentation — component examples and composition guidance. Check your installed version's public types for its exact API.
- Design tokens
- Package versions
Use the npm package page to check available versions. Installing or upgrading a package does not automatically change how your application consumes it.
License
MIT.
