fluid-ui-native
v1.0.2
Published
Performant, accessible React Native & Expo UI, Media & Utility Ecosystem with Material You and Adaptive Low-End Device Engine
Maintainers
Readme
Fluid UI Native
A clean, fast UI component library for React Native and Expo.
npm install fluid-ui-nativeWhat to Do After Installing (Step-by-Step)
Step 1: Install Peer Dependencies (Optional)
If you want vector icons, install react-native-svg:
# For Expo apps:
npx expo install react-native-svg
# For React Native CLI:
npm install react-native-svg
cd ios && pod install # (iOS only)Step 2: Set Up the Providers in Your Root File
Wrap your app in DynamicThemeProvider (for colors and dark mode) and FluidToastPortal (for popup toasts):
If you use Expo Router (app/_layout.tsx):
import { Slot } from 'expo-router';
import { DynamicThemeProvider, FluidToastPortal } from 'fluid-ui-native';
export default function RootLayout() {
return (
<DynamicThemeProvider seedColor="#6366F1" mode="system">
<Slot />
<FluidToastPortal />
</DynamicThemeProvider>
);
}If you use standard React Native (App.tsx):
import React from 'react';
import { SafeAreaView } from 'react-native';
import { DynamicThemeProvider, FluidToastPortal, FluidButton, FluidCard, FluidText, toast } from 'fluid-ui-native';
export default function App() {
return (
<DynamicThemeProvider seedColor="#6366F1" mode="system">
<SafeAreaView style={{ flex: 1, padding: 16 }}>
<FluidCard style={{ padding: 20 }}>
<FluidText variant="titleLarge">Hello Fluid UI!</FluidText>
<FluidText variant="bodyMedium" color="#64748B" style={{ marginTop: 6 }}>
Your app is ready. Start importing any of the 84 components.
</FluidText>
<FluidButton
title="Show Toast Notification"
variant="filled"
onPress={() => toast.success('Fluid UI is working!')}
style={{ marginTop: 16 }}
/>
</FluidCard>
</SafeAreaView>
<FluidToastPortal />
</DynamicThemeProvider>
);
}How to Customize Colors & Themes
Fluid UI uses a Material You HCT color system that automatically generates WCAG AAA/AA accessible color schemes for both Light and Dark modes.
1. Changing the Primary Seed Color
Pass any color format (Hex, OKLCH, RGB, HSL, or Named Color) to seedColor:
// Using Hex
<DynamicThemeProvider seedColor="#6366F1">
// Using OKLCH (CSS 4)
<DynamicThemeProvider seedColor="oklch(0.65 0.24 265)">
// Using RGB / RGBA
<DynamicThemeProvider seedColor="rgb(16, 185, 129)">
// Using HSL
<DynamicThemeProvider seedColor="hsl(350, 89%, 60%)">
// Using Named Color (emerald, indigo, rose, amber, purple, ocean, etc.)
<DynamicThemeProvider seedColor="emerald">2. Toggling Light & Dark Mode
Use the useFluidTheme hook inside any component:
import { useFluidTheme, FluidButton } from 'fluid-ui-native';
function HeaderThemeToggle() {
const { mode, setMode, isDark, toggleMode } = useFluidTheme();
return (
<FluidButton
title={isDark ? 'Switch to Light' : 'Switch to Dark'}
onPress={toggleMode}
/>
);
}3. Using Semantic Theme Colors in Custom Components
Use the useColors() hook to access active theme tokens:
import { View, Text } from 'react-native';
import { useColors } from 'fluid-ui-native';
function CustomCard() {
const colors = useColors();
return (
<View style={{ backgroundColor: colors.surface, borderColor: colors.outlineVariant }}>
<Text style={{ color: colors.onSurface }}>Heading</Text>
<Text style={{ color: colors.primary }}>Primary Brand Text</Text>
</View>
);
}How to Use & Customize Icons
Fluid UI comes with built-in 24x24 scalable vector icons that require zero font setup.
1. Using Built-in Icons
import {
HomeIcon, SearchIcon, BellIcon, ShoppingCartIcon,
UserIcon, CameraIcon, QrCodeIcon, MessageIcon, PhoneIcon,
CheckIcon, CloseIcon, LockIcon, StarIcon, ArrowLeftIcon
} from 'fluid-ui-native';
// Customize size, color, strokeWidth
<SearchIcon size={22} color="#6366F1" strokeWidth={2.5} />
<StarIcon size={18} color="#F59E0B" filled={true} />2. Passing Custom Icons to Components
Every component has custom icon slots where you can pass Lucide, Ionicons, MaterialIcons, or your own SVGs:
import { FluidButton, FluidEmptyState, FluidMessageInput } from 'fluid-ui-native';
import { Heart, Send, Sparkles } from 'lucide-react-native'; // Optional external icons
// Button with custom leading icon
<FluidButton
title="Favorite"
icon={<Heart size={18} color="#FFFFFF" />}
/>
// Empty state with custom graphic/icon
<FluidEmptyState
title="No Favorites Found"
description="Items you favorite will appear here."
icon={<Sparkles size={40} color="#6366F1" />}
actionTitle="Explore Catalog"
onActionPress={() => {}}
/>
// Message input with custom icons
<FluidMessageInput
onSend={(msg) => console.log(msg)}
attachIcon={<Sparkles size={20} color="#94A3B8" />}
/>Main Components Guide & Examples
1. Camera Viewfinder & QR/Barcode Scanner
4-in-1 Camera Viewfinder (FluidCamera):
import { FluidCamera } from 'fluid-ui-native';
<FluidCamera
mode="photo" // 'photo' | 'video' | 'qr' | 'document'
flashMode="auto" // 'off' | 'on' | 'auto' | 'torch'
zoom={1} // 0.5, 1, 2
showGrid={true}
onCapture={(mode) => console.log('Captured photo in mode:', mode)}
onToggleCamera={() => console.log('Camera flipped')}
/>Glowing Laser QR & Barcode Scanner (FluidQRScanner):
import { FluidQRScanner } from 'fluid-ui-native';
<FluidQRScanner
hasPermission={true}
vibrateOnScan={true} // Triggers haptic vibration on successful scan
onRequestPermission={() => console.log('Request permission')}
onScan={(data) => console.log('Scanned Barcode / QR:', data)}
/>2. Security: Passcode Keypad & Pattern Lock
Banking Numeric Passcode Keypad (FluidPasscodeKeypad):
import { FluidPasscodeKeypad } from 'fluid-ui-native';
<FluidPasscodeKeypad
length={4}
title="Enter Security PIN"
shuffleKeys={true} // Shuffles numbers for banking grade security
hasError={false} // Set true to trigger shake animation
onComplete={(pin) => console.log('PIN verified:', pin)}
onBiometricPress={() => console.log('Trigger FaceID')}
/>3x3 Android Pattern Unlock Grid (FluidPatternLock):
import { FluidPatternLock } from 'fluid-ui-native';
<FluidPatternLock
size={300}
onPatternComplete={(pattern) => {
// Array of connected node indices e.g. [0, 1, 2, 4, 6]
console.log('Pattern drawn:', pattern);
}}
/>3. Chat, Voice Notes & Messaging
Chat Message Input with Voice Recording (FluidMessageInput):
import { FluidMessageInput } from 'fluid-ui-native';
<FluidMessageInput
placeholder="Type a message..."
onSend={(text) => console.log('Send text:', text)}
onAttach={() => console.log('Open photo gallery')}
onVoiceRecordStart={() => console.log('Hold-to-record voice started')}
onVoiceRecordEnd={() => console.log('Voice note recorded')}
/>Chat Bubble with Reactions & Status Checks (FluidChatBubble):
import { FluidChatBubble } from 'fluid-ui-native';
<FluidChatBubble
text="Hey! Can you send me the invoice PDF?"
timestamp="10:42 AM"
isSender={false}
status="read" // 'sending' | 'sent' | 'delivered' | 'read'
reactions={[{ emoji: '+1', count: 2, userReacted: true }]}
onReactionPress={(emoji) => console.log('Reacted:', emoji)}
/>Voice Note Audio Waveform Player (FluidAudioMessage):
import { FluidAudioMessage } from 'fluid-ui-native';
<FluidAudioMessage
durationSeconds={45}
isPlaying={false}
playbackSpeed={1.5}
onTogglePlay={() => {}}
onSpeedChange={(newSpeed) => console.log('Speed:', newSpeed)}
/>4. Saved Address Selector with GPS Coordinates (FluidAddressPicker):
import { FluidAddressPicker } from 'fluid-ui-native';
<FluidAddressPicker
addresses={[
{
id: '1',
type: 'home',
title: 'Home',
addressLine: '124 Market Street, Suite 400',
city: 'San Francisco',
postalCode: '94103',
latitude: 37.7749,
longitude: -122.4194,
isDefault: true
},
{
id: '2',
type: 'work',
title: 'Office HQ',
addressLine: '500 Howard St, Floor 12',
city: 'San Francisco',
postalCode: '94105',
latitude: 37.7892,
longitude: -122.3972
},
]}
selectedId="1"
onSelectAddress={(addr) => console.log('Selected:', addr.title, addr.latitude, addr.longitude)}
onUseCurrentLocation={() => console.log('GPS Location button clicked')}
onAddNewAddress={() => console.log('Open add address modal')}
/>5. File Upload Dropzone (FluidFileUploader):
import { FluidFileUploader } from 'fluid-ui-native';
<FluidFileUploader
maxSizeMB={10}
maxFiles={5}
allowedExtensions={['pdf', 'docx', 'jpg', 'png']}
onFilesSelected={(files) => console.log('Files to upload:', files)}
/>6. Interactive FAQ Accordion List (FluidAccordionGroup):
import { FluidAccordionGroup } from 'fluid-ui-native';
<FluidAccordionGroup
allowMultiple={false} // Set true to allow multiple FAQs open at once
items={[
{ id: 1, question: 'Does Fluid UI work with Expo?', answer: 'Yes, full iOS, Android, and Web Expo support out of the box.' },
{ id: 2, question: 'Do I need NativeWind?', answer: 'No! It works with regular inline styles or our built-in tw() helper.' },
{ id: 3, question: 'Can I use custom icons?', answer: 'Yes! All components accept custom icon props.' },
]}
/>7. Gamification: Spin-to-Win Wheel & Scratch Card
Lucky Draw Spin Wheel (FluidSpinWheel):
import { FluidSpinWheel } from 'fluid-ui-native';
<FluidSpinWheel
segments={[
{ label: '$10 Off', color: '#6366F1' },
{ label: 'Free Shipping', color: '#10B981' },
{ label: '20% Discount', color: '#F59E0B' },
{ label: 'Try Again', color: '#94A3B8' },
{ label: '$50 Gift Card', color: '#EC4899' },
{ label: '5% Cash', color: '#3B82F6' },
]}
onSpinComplete={(winner) => alert(`You won: ${winner.label}!`)}
/>Scratch-to-Reveal Reward Card (FluidScratchCard):
import { FluidScratchCard, FluidText } from 'fluid-ui-native';
<FluidScratchCard
width={300}
height={160}
revealThresholdPercent={50}
onRevealed={() => console.log('Reward revealed!')}
>
<View style={{ alignItems: 'center', justifyContent: 'center', flex: 1 }}>
<FluidText variant="headlineSmall" weight="bold" color="#10B981">
PROMO: FLUID50
</FluidText>
<FluidText variant="bodySmall">50% off your next checkout</FluidText>
</View>
</FluidScratchCard>8. Charts: Speedometer Gauge, Donut & Bar Charts
import { FluidGaugeChart, FluidDonutChart, FluidCharts } from 'fluid-ui-native';
// Credit / Health Score Radial Speedometer Gauge
<FluidGaugeChart
value={750}
minValue={300}
maxValue={850}
unit="pts"
statusLabel="Excellent"
/>
// Circular Donut Chart with Center Metric Label
<FluidDonutChart
data={[
{ label: 'Completed', value: 70, color: '#10B981' },
{ label: 'In Progress', value: 20, color: '#6366F1' },
{ label: 'Pending', value: 10, color: '#F59E0B' },
]}
centerMetric="70%"
centerLabel="Efficiency"
/>
// Tactile Bar Chart
<FluidCharts
type="bar"
data={[
{ label: 'Mon', value: 45 },
{ label: 'Tue', value: 80 },
{ label: 'Wed', value: 65 },
{ label: 'Thu', value: 95 },
{ label: 'Fri', value: 75 },
]}
/>3 Flexible Ways to Style
1. Built-in tw helper (No Tailwind setup needed)
import { View, Text } from 'react-native';
import { tw } from 'fluid-ui-native';
<View style={tw('flex-row items-center justify-between p-4 bg-white rounded-xl shadow-md')}>
<Text style={tw('font-bold text-lg text-black')}>Order Details</Text>
</View>2. NativeWind v4 (className)
<FluidButton title="Submit" className="bg-primary hover:bg-primary/90 p-4 rounded-xl" />3. Standard React Native style prop
<FluidButton title="Cancel" style={{ padding: 12, borderRadius: 8 }} />CLI Setup (Optional: Copy Component Source Files)
If you prefer copying components directly into your project (like shadcn/ui):
# 1. Initialize configuration & theme tokens
npx fluid-ui-native init
# 2. Add individual components to your @/components/ui folder
npx fluid-ui-native add button input card sheet accordion qr-scannerAll 84 Components Reference
| Category | Components |
|---|---|
| Inputs | FluidButton, FluidInput, FluidOutlinedInput, FluidOtpInput, FluidPasscodeKeypad, FluidPatternLock, FluidSignaturePad, FluidSwitch, FluidCheckbox, FluidSegmentedControl, FluidSlider, FluidPriceSlider, FluidSelect, FluidWheelPicker, FluidDatePicker, FluidCalendarRangePicker, FluidRating, FluidSearchBar, FluidFloatingSearchFilter, FluidFileUploader, FluidMessageInput, FluidSpeedDialMenu, FluidSwipeButton, FluidSlideToUnlock, FluidColorPicker, FluidFAB |
| Surfaces & Cards | FluidCard, GlassSurface, FluidBadge, FluidChip, FluidTabs, FluidSwipeableRow, FluidDivider, FluidCarousel, FluidTable, FluidTimeline, FluidTree, FluidHeader, FluidStickyHeaderScrollView, FluidBottomNav, FluidStepper, FluidStatusDot, FluidChatBubble, FluidLiveTrackingCard, FluidCouponCard, FluidAddressPicker, FluidEmptyState, FluidBadgeNotificationCenter, FluidCodeBlock |
| Modals & Sheets | FluidSheet, FluidDialog, FluidDrawer, FluidModal, FluidActionSheet, FluidCheckoutDrawer, FluidMenu, FluidAccordion, FluidAccordionGroup, FluidTooltip, FluidBiometricPrompt, FluidReactionPicker, FluidCommentSheet, FluidOnboardingTour, FluidSpotlightTour |
| Media & Scanner | FluidCamera, FluidQRScanner, FluidDocumentScanner, FluidImage, FluidImageViewer, FluidStoryViewer, FluidVideo, FluidAudio, FluidAudioMessage, FluidAudioWaveformRecorder, FluidPinchZoomView, FluidAvatar, FluidAvatarGroup, FluidLazyLoader |
| Charts | FluidCharts (Bar / Sparkline), FluidGaugeChart, FluidDonutChart, FluidActivityHeatmap |
| Feedback | FluidToastPortal, toast, FluidSkeleton, FluidConfetti, FluidSpinWheel, FluidScratchCard, FluidBannerAlert |
FAQ & Troubleshooting
Q: Do I need to install NativeWind or Tailwind?
No. You can style components using standard React Native style={{}} or our built-in style={tw('p-4 bg-white')} helper without installing any extra styling libraries.
Q: Can I use custom icons from Lucide or FontAwesome?
Yes. All components have an icon?: React.ReactNode slot where you can pass any custom icon component.
Q: What color formats can I pass to seedColor?
You can pass Hex (#6366F1), OKLCH (oklch(0.65 0.24 265)), RGB (rgb(99, 102, 241)), HSL (hsl(239, 84%, 67%)), or Named Colors (emerald, indigo, rose).
License
MIT (c) Fluid UI Team
