Bloom is the UI library every Oxy app is built with.
One component set for React Native, Expo and the web, with the same props on every platform.
|
Components, hooks and design tokens published as Styling is NativeWind classes throughout. There are no colour props and no wrapper components to theme a button, because a second way to set a colour is a second thing that can disagree. |
Bloom is the presentation layer of oxy. It knows nothing about identity or the network, so it has no dependency on the Oxy SDK and can be used on its own. Where an app does use the SDK, the two meet at one seam: register |
bun add @oxy.so/bloomPeer dependencies
Always required:
| Package | Range |
|---|---|
react |
>=18.0.0 |
react-dom |
>=18.0.0 |
react-native |
>=0.73.0 |
react-native-safe-area-context |
>=5.0.0 |
react-native-screens |
>=3.16.0 |
nativewind |
>=5.0.0 |
Required by specific surfaces, and by more of them than you would guess:
| Package | Range | Needed by |
|---|---|---|
react-native-reanimated |
>=3.13.0 |
Dialog, BottomSheet, toast, Loading, on the web too |
react-native-gesture-handler |
>=2.16.1 |
Dialog, BottomSheet, swipe to dismiss on toasts |
react-native-svg |
>=13.0.0 |
icons, Avatar in any non-circular shape |
react-native-keyboard-controller |
>=1.11.4 |
keyboard aware surfaces |
expo, expo-blur, expo-font, expo-haptics, expo-image, expo-symbols |
see package.json |
native effects, fonts, haptics, images and SF Symbols |
expo-glass-effect |
>=0.1.9 |
glass surfaces |
expo-router |
>=3.0.0 |
the expo-router variants of tabs, scroll and tab-bar |
@react-native-community/netinfo |
>=11.1.0 |
connection-status |
On native, wrap the app root in GestureHandlerRootView from react-native-gesture-handler, or the bottom sheet pan gestures will not fire.
Bloom follows the clean cut rule, so there are no @deprecated aliases and no old name shims. If a symbol you import was removed, nothing re-exports it and the build fails. docs/migrating-to-2.0.mdx is the bridge: the five removed families and what replaces them, the Remix icon set and its codemod, Inter as the UI face, every changed default, and the Breathe License.
The icon codemod ships with the package:
node node_modules/@oxy.so/bloom/scripts/migrate-icons-to-remix.mjs <app-root> --dry-run --diffComing from 0.x, read docs/migrating-to-1.0.mdx first. Both guides ship inside the package, so the copy under node_modules/@oxy.so/bloom/docs/ describes the version you installed.
Mount BloomProvider once, at the very top of the app. It composes every piece of app wide Bloom state, theme, haptics, image resolution, scroll restoration and tab bar minimise progress, so none of them can end up at the wrong depth.
import { BloomProvider } from '@oxy.so/bloom/provider';
<BloomProvider
defaultMode="system"
defaultColorPreset="blue"
persistKey="app.theme"
storage={storage}
imageResolver={(id, variant) => oxyServices.getFileDownloadUrl(id, variant)}
>
<App />
</BloomProvider>Everything scrollable must sit under it. useScrollRestoration() throws outside its provider, so a list rendered beside the root, a right rail or an overlay, crashes that screen.
Outlets are deliberately not included, because where they sit in the tree is a real application decision and a second mount duplicates every surface they render. Mount these yourself, under BloomProvider: ToastOutlet, the PortalProvider and PortalOutlet pair from @oxy.so/bloom/portal, and SurfaceHost (which renders alert(), confirm(), prompt() and everything else on the surface stack).
import { Button } from '@oxy.so/bloom/button';
import { toast } from '@oxy.so/bloom/toast';
<Button onPress={() => toast.success('Saved')}>Save</Button>|
Four modes
import { useTheme } from '@oxy.so/bloom/theme';
const theme = useTheme();
// theme.colors.primary, theme.colors.text, theme.isDark
|
Named colour presets
Presets use the shared colour engine, with authored accent pairings and token values where specified, for light and dark. Dynamic seed colours use the same role-generation and colour-policy pipeline. |
Bloom publishes each component family through a subpath export. Importing from the subpath rather than the root keeps a bundle to what it actually renders.
Icons go one step further: every glyph is its own subpath, @oxy.so/bloom/icons/<RiName>. Metro does not tree-shake, so the flat @oxy.so/bloom/icons barrel ships all 480 glyphs to any app that names one — see icons for the measurement and when to reach for which import. The barrel keeps working unchanged — it stays an exact exports key, and an exact key beats a pattern everywhere.
| Group | Exports |
|---|---|
| Providers and theme | provider, theme, theme-toggle, color-presets, preset-vars, design-tokens, tailwind-preset, styles, control-surface, hooks |
| App shell and navigation | app-shell, page-header, sidebar, rail, breadcrumb, pagination, tabs, tab-bar, layout, content-panel |
| Overlays | dialog, alert-dialog, bottom-sheet, popover, context-menu, dropdown-menu, menubar, tooltip, overlay, portal, teleport, surfaces, settings-modal |
| Actions | button, button-group, social-button, fab, frosted-icon-button, pressable-scale, subtle-hover |
| Forms | text-field, textarea, phone-input, input-otp, field, input-group, label, select, command, checkbox, radio, switch, slider, segmented-control, search, date-picker, file-upload, auth-card, stepper, rating, wizard |
| Layout and lists | grid, list, scroll, settings-list, card, cover-header, accordion, aspect-ratio, divider, item, carousel |
| Data and charts | table, data-table, chart-cards, stat-cards, calendar, composition-bar, stat-bar, activity-heatmap, recent-hires-card, patient-info-card, important-alerts-card, agent-limits-card, ai-profile-card |
| Music and media | media-card, media-controls, media-header, media-player, media-shelf, track-list, queue-panel, lyrics, music-library, creator-studio, sortable-media |
| Housing | home-search, listing-actions, listing-editor, offering-badge, place-reviews, property-insights, tenancy, eviction |
| Stays and booking | listing-card, listing-details, stay-search, stay-filters, booking, category-bar, map-marker |
| AI and agents | agent-chat, ai-chat, composer-panel, composer-loader, agent-thinking, agent-log, agent-progress, task-list, web-search, questionnaire |
| Identity and media | shapes, avatar, avatar-group, hover-card, user-hover-card, image-resolver, image-aspect-ratio-cache, zoomable-image-gallery, zoomable-media-gallery, media-flight, media-inset-border, progressive-blur, fill |
| Chat | chat-list, chat-screen, chat-composer, chat-people, chat-indicators, message-bubble, message-media, call-ui |
| Feedback | toast, notification, notification-center, announcement, admonition, loading, skeleton, error-boundary, badge, chip, kbd, code, link-preview, connection-status, connection-dots |
| Motion and assets | motion, animated-check, icon-circle, radio-indicator, icons, typography, fonts |
tabs, scroll and tab-bar each ship an /expo-router variant for apps on Expo Router.
Component guides live in docs/, one .mdx per family, and they ship inside the package at node_modules/@oxy.so/bloom/docs/. The copy you read there always describes the version you installed, which matters most for migrating to 3.0.
Start with getting started, theme and design tokens. Then per surface: app shell, sidebar, data table, chart cards, composer panel, dialog, bottom sheet, toast, alert, dropdown menu, select, context menu, button, avatar, text field, settings list, tab bar and loading.
The theme reference is in README.theme.md.
bun install
bun run build # react-native-builder-bob, then verify the published shape
bun run typescript # type check
bun run test # jest
bun run storybook # component workshop on port 6006
bun run clean # remove lib/build regenerates the platform export map and the theme CSS first, then verifies the package it just produced. If that verification fails, the package is wrong, not the check.
Issues and pull requests are welcome. Please run bun run typescript and bun run test first. Org wide contributing notes, the security policy and the code of conduct live in the organisation profile.
The Breathe License 1.0, The Oxy Collective, Inc.