TypeScript-first · Apache 2.0 · 1K+ downloads

The React Native UI
library that gets
out of your way

35+ production-ready components, imperative services, portal-based overlays, and a complete design token system. Install once. Ship forever.

★ Star on GitHub
35+Components
5Hook APIs
5Services
100%TypeScript
0Config needed
Install in seconds
npm install fluent-styles
yarn add fluent-styles

Why fluent-styles

Everything included.
Nothing to configure.

Designed for teams that value speed without sacrificing quality or consistency.

Zero config
Wrap with GlobalPortalProvider and start building. No theme setup, no boilerplate, no providers to wire up.
🎯
Imperative services
Call toastService or dialogueService from anywhere — Axios interceptors, Redux middleware, outside React entirely.
🔷
TypeScript first
Every prop, every color token, every hook return type is fully typed. Autocomplete works out of the box. No any needed.
🎨
Token overrides
Every component takes a typed colors prop. Per-screen themes, dark mode, brand colors — all without CSS.
🌀
Portal UI
Toasts, modals, drawers, action sheets render above everything via a dual-layer portal. No z-index conflicts ever.
📦
Flat style props
No StyleSheet.create. Pass margin, padding, borderRadius directly as props. Clean code, native performance.

Quick start

One wrapper.
Everything works.

The portal provider is the only setup step. After that, every component, hook, and service is ready to use.

App.tsx
import { GlobalPortalProvider } from 'fluent-styles'

export default function App() {
  return (
    <GlobalPortalProvider>
      <YourNavigator />
    </GlobalPortalProvider>
  )
}

// Use from anywhere — even outside React
import { toastService, dialogueService } from 'fluent-styles'

toastService.success('Profile saved!')
toastService.error('Upload failed', 'Check your connection')

const ok = await dialogueService.confirm({
  title: 'Delete project?',
  destructive: true,
})

Theming

Full token control.
No CSS needed.

Every component ships with typed color token maps. Override exactly what you need, inherit the rest.

theme-override.tsx
import { theme, palettes, TabBar } from 'fluent-styles'

// Color scales (50–900)
theme.colors.indigo[500] // '#6366f1'
theme.colors.rose[600] // '#e11d48'

// Per-component token override
<TabBar
  options={tabs}
  colors={{
    background: palettes.indigo[50],
    activeText: palettes.indigo[600],
    indicator: palettes.indigo[600],
    border: palettes.indigo[200],
  }}
/>

Start building today

One install. Everything included. Zero config.

View on npm

Component Library

35+ production-ready components

Every component ships with variants, sizes, color overrides, and full TypeScript types.

Hooks & Services

Two ways to trigger every overlay

Use hooks inside React components, or call services directly from anywhere in your app.

Portal Architecture

Render above
everything

Dual-layer portal system. GlobalPortalProvider handles imperative service calls — usable outside React. PortalManager handles hook APIs inside components.

toastService.success(msg)
notificationService.show(opts)
dialogueService.confirm(opts)
actionSheetService.present(content)
loaderService.wrap(asyncFn)

Getting started

Installation

Install the package and its peer dependency.

terminal
# npm
npm install fluent-styles

# yarn
yarn add fluent-styles

# peer dependency
npm install react-native-safe-area-context

Quick start

Three steps to get everything working.

1
Wrap with GlobalPortalProvider
Place it at the root of your app. This enables all portal-based UI — toasts, notifications, loaders, dialogues, drawers.
2
Add PortalManager for hook APIs
If you use useToast, useDialogue, or other hook variants inside components, nest a PortalManager inside the provider.
3
Import and use anything
Every component, hook, service, and token is available directly from the fluent-styles package.
App.tsx
import { GlobalPortalProvider, PortalManager } from 'fluent-styles'

export default function App() {
  return (
    <GlobalPortalProvider>
      <PortalManager>
        <YourNavigator />
      </PortalManager>
    </GlobalPortalProvider>
  )
}

Portal system

Fluent Styles uses a dual-layer portal architecture.

GlobalPortalProvider — Enables imperative services (toastService, loaderService etc.). These work from anywhere in your codebase including outside React — Axios interceptors, Redux middleware, navigation helpers.

PortalManager — Enables hook APIs (useToast, useDialogue etc.) inside React components.
anywhere.ts
import { portal } from 'fluent-styles'

// Low-level portal for advanced use
const id = portal.show(<MyWidget />, {
  position: 'top',
  backdrop: false,
})
setTimeout(() => portal.hide(id), 3000)

Theming & tokens

The full design token system is exported for use in your own components.

tokens.ts
import { theme, palettes, lightColors, darkColors, fontStyles } from 'fluent-styles'

// Color scales (50–900)
theme.colors.indigo[500] // '#6366f1'
theme.colors.rose[600] // '#e11d48'
theme.colors.gray[100] // '#f4f4f5'

// Typography
theme.fontSize.small
theme.fontSize.large
theme.fontWeight.semiBold
theme.fontWeight.bold

// Per-component color maps
TAB_BAR_COLORS_LIGHT // default light tokens for TabBar
POPUP_COLORS_DARK // default dark tokens for Popup
Every component accepts a colors prop typed as Partial<ComponentColors>. You only need to specify the tokens you want to override — the rest inherit from the defaults.

Flat style props

Pass ViewStyle and TextStyle props directly on components — no StyleSheet.create needed.

example.tsx
// ✅ fluent-styles way — flat props
<Stack
  horizontal
  gap={12}
  padding={16}
  borderRadius={12}
  backgroundColor={theme.colors.white}
/>

// ❌ old way — StyleSheet.create
const styles = StyleSheet.create({
  row: {
    flexDirection: 'row',
    gap: 12, padding: 16, borderRadius: 12,
    backgroundColor: '#fff',
  },
})

TypeScript

Everything is typed. Props, tokens, hook returns, service options.

typed.tsx
import type {
  TabBarColors, PopupColors, DrawerColors,
  ToastVariant, DialogueAction,
  FitnessLevel, TableColumn,
} from 'fluent-styles'

// Strongly typed color override
const myColors: Partial<TabBarColors> = {
  activeText: '#6366f1',
  indicator: '#6366f1',
}

// Fully typed table columns
const cols: TableColumn<User>[] = [
  { key: 'name', title: 'Name', sortable: true },
  { key: 'role', title: 'Role', width: 120 },
]