@consensys/ds3 v0.0.2
@consensys/ds3
š§ Note: This package is under active development. While we're working hard to make it production-ready, please be aware that APIs and features may change. We welcome your feedback and contributions as we continue to improve!
š Ultimate cross-platform React components that feel native everywhere
Build breathtaking interfaces for both web and React Native with a single component library that respects each platform's conventions while providing a unified developer experience.
// One import. Any platform. Native everywhere.
import { Button, Input, Icon } from '@consensys/ds3';
⨠Standout Features
š True Cross-Platform - Components work natively on web and React Native with platform-specific optimizations
š§ Framework Agnostic - Seamless integration with Vite, Expo and more through @consensys/ds3-config plugins
š§© Compound Components - Simple by default, infinitely customizable when needed
š Dual API - Use familiar web APIs or React Native patterns - your choice, no compromise
āæ Accessibility Built-in - Ship inclusive experiences without extra effort
šØ Consistent Design - Share color schemes and tokens across platforms
š Pluggable Styling - Tailwind CSS + NativeWind for unified styling that feels native everywhere
š¼ļø Universal SVG - Use your favorite icon libraries seamlessly on any platform
š Get Started
pnpm add @consensys/ds3
For detailed framework setup and configuration, see the @consensys/ds3-config documentation.
š Component Library
DS3 UI gives you production-ready components for building modern interfaces:
Core Components
- Button - Pressable controls with multiple variants, states, and compositions
- Checkbox - Selection controls with accessible states and custom icons
- Heading - Semantic typography with consistent hierarchy across platforms
- Icon - Universal SVG rendering with perfect platform adaptation
- Input - Text fields with validation, icons, and platform-specific behaviors
- Spinner - Loading indicators with customizable animations
- Switch - Toggle controls with smooth animations
- Text - Typography components with consistent styling everywhere
Form Components
- Field - Foundational form fields with proper labeling and structure
- Fields - High-level form controls with built-in validation and accessibility
Coming Soon
- Dialog - Modal dialog experiences
- Select - Dropdown selection menus
- Avatar - User representation components
- Card - Content containers with flexible layouts
- Badge - Status indicators and counters
šļø Architectural Excellence
DS3 UI is built on six powerful architectural patterns that work together to deliver exceptional developer and user experiences:
1. š Platform Adaptation
Components intelligently adapt to their environment while maintaining consistent APIs:
// Same import, same API, platform-perfect behavior
import { Input } from '@consensys/ds3';
// Works perfectly on web and native
<Input
placeholder="Enter your name"
color="primary"
/>
DS3 UI components follow a consistent organization pattern that enables cross-platform functionality:
Component Architecture
File | Purpose |
---|---|
Component.tsx | React Native implementation |
Component.web.tsx | Web implementation |
Component.shared.tsx | Shared compound elements (Icon, Text, etc.) |
context.ts | State sharing for compound components |
styles.ts | Shared CVA styling definitions |
utils.ts | Dual-API handling |
types.ts | TypeScript type definitions |
index.ts | Named exports |
Implementation Strategies
DS3 UI uses two main approaches to implement cross-platform components:
1. Custom Implementation
Most components like <Button />
, <Input />
, and <Icon />
use platform-specific implementations:
// Input.tsx (React Native specific)
export const Input = (props) => <TextInput {...props} />;
// Input.web.tsx (Web specific)
export const Input = (props) => <input {...props} />;
2. Primitives-Based Implementation
Some components build on existing accessibility primitives:
// Checkbox.tsx uses RN Primitives
import * as CheckboxPrimitive from '@rn-primitives/checkbox';
// Checkbox.web.tsx uses Radix UI
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
These leverage Radix UI (web) and RN Primitives (React Native) for consistent behavior and accessibility.
2. š§© Compound Components
Simple by default, infinitely customizable when needed:
// Simple usage - clean and concise
<Button color="primary">
Sign Up
</Button>
// Advanced usage - full control over structure and styling
<Button variant="outline" color="primary" className="px-8 rounded-full">
<Button.Icon icon={Mail} className="mr-2" />
<Button.Text className="font-bold tracking-wide">Contact Us</Button.Text>
<Button.Spinner loadingIcon={RefreshCw} className="ml-3 animate-spin" />
</Button>
Power features:
- ā” Context sharing - Child components automatically inherit parent state
- šļø Precise control - Position and style each element exactly how you want
- š Dynamic rendering - Show/hide elements based on component state
For a deeper dive into the pattern, see the Patterns.dev guide.
3. š Framework Integration
Consistent experience across multiple React frameworks:
// Works in React DOM (Vite)
// Works in React Native (Expo)
// Works in Next.js (coming soon)
import { Button, Input } from '@consensys/ds3';
Integration features:
- šļø Framework plugins - Easy setup with @consensys/ds3-config framework-specific plugins
- š§° Configuration presets - Optimized defaults for each framework
- š Shared APIs - Consistent component behavior regardless of framework
Framework-specific optimizations are handled by @consensys/ds3-config plugins, allowing your components to work seamlessly in any React environment.
4. āæ Accessibility By Default
Ship accessible experiences without extra effort:
- š¤ ARIA mapping - Web attributes automatically map to native equivalents
- āØļø Keyboard navigation - Full keyboard support on every platform
- š£ļø Screen reader optimization - Proper roles and states for assistive technology
- š Focus management - Visual indicators and proper focus trapping
š Accessibility Prop Mapping
The library automatically maps accessibility props between platforms. Here are a few common examples:
Web Props | Native Props | Component |
---|---|---|
aria-disabled | accessibilityState.disabled | Button, Input |
aria-busy | accessibilityState.busy | Button, Input |
role="button" | accessibilityRole="button" | Button |
// Web accessibility
<Button
aria-disabled={isLoading}
aria-busy={isLoading}
role="button"
>
Submit
</Button>
// Native accessibility
<Button
accessibilityState={{
disabled: isLoading,
busy: isLoading
}}
accessibilityRole="button"
>
<Button.Text>Submit</Button.Text>
</Button>
5. šØ Unified Styling
One styling system, perfect everywhere:
// Consistent styling API across platforms
<Text
size="lg"
weight="bold"
color="primary"
className="underline opacity-90" // Works on web and native!
/>
Style features:
- š Tailwind + NativeWind - Use familiar Tailwind CSS classes everywhere through NativeWind
- š Variants - Consistent styling API with class-variance-authority (CVA)
- šļø Theme tokens - Shared design tokens for colors, spacing, and typography
6. š Dual API
While Platform Adaptation handles the underlying implementation differences, Dual API gives you the freedom to write code in your preferred style. Whether you're a web developer or React Native developer, you can use the APIs you're most comfortable with.
Dual API features:
- š Web-first development - Use familiar DOM APIs (
onClick
,onChange
,type
) - š± Native-first development - Use React Native APIs (
onPress
,onChangeText
) - š”ļø Type safety - Full TypeScript support for both platforms
- š Automatic conversion - Props map correctly between platforms
- š§ Smart detection - Components adapt to how you use them
š The Rules
š Web-only Development
- Use ONLY web props (
onClick
,onChange
,type
) - Get full DOM access and browser features
- Perfect for web-only applications
- Use ONLY web props (
š± Native/Hybrid Development
- Use ONLY native props (
onPress
,onChangeText
) - Consistent with React Native patterns
- Works across all platforms
- Use ONLY native props (
ā ļø Never Mix APIs
// ā INCORRECT: Using web props in native/hybrid code <Button onClick={() => {}} // Will be ignored on native! onPress={handlePress} > <Button.Text>Mixed Props Button</Button.Text> </Button> // ā CORRECT: š Web-only code can use web props <Button onClick={handleClick} // Perfectly fine in web-only code! > <Button.Text>Web Button</Button.Text> </Button> // ā CORRECT: š±š Native/hybrid code must use native props <Button onPress={handlePress} > <Button.Text>Native Button</Button.Text> </Button>
š Prop Mapping
For hybrid applications, the library automatically maps native props to web props. This one-way mapping ensures React Native code works seamlessly on web. Here are a few common examples:
Native Props | Web Props | Component |
---|---|---|
onPress | onClick | Button |
onChangeText | onChange | Input |
secureTextEntry | type="password" | Input |
ā ļø Important Rules: 1. Never use web props in native code - they will be silently ignored 2. Never mix web and native props - choose one style and stick with it
š Type-Safe Events
The library provides platform-specific event types for type safety:
import type { WebClickEvent, NativePressEvent } from '@consensys/ds3';
// š Web events
<Button onClick={(e: WebClickEvent) => console.log(e.currentTarget)}>
Click Me
</Button>
// š± Native events
<Button onPress={(e: NativePressEvent) => console.log(e.nativeEvent)}>
<Button.Text>Press Me</Button.Text>
</Button>
Web Types | Native Types | Description |
---|---|---|
WebClickEvent | NativePressEvent | Button click/press events |
WebFocusEvent | NativeFocusEvent | Focus/blur events |
WebChangeEvent | NativeChangeEvent | Input change events |
šÆ Platform Adaptation vs Dual API
- Platform Adaptation: Handles the underlying implementation differences (DOM vs Native)
- Dual API: Gives you the freedom to write code in your preferred style
7. š Slot Pattern
Replace any component part with your own elements:
// Button as a link using asChild
<Button variant="solid" color="primary" asChild>
<a href="https://example.com">Visit Website</a>
</Button>
// Button as a router link
<Button variant="outline" color="secondary" asChild>
<Link to="/dashboard">Go to Dashboard</Link>
</Button>
The Slot pattern allows you to replace a component's default root element with your own custom element, while preserving all styling, behavior, and accessibility features.
When you pass asChild={true}
to a component:
- The component renders a
Slot
component instead of its default element - The
Slot
captures all props from the parent component - It applies those props to the first child element you provide
- The child element becomes the new root, inheriting all behavior
The rendered DOM with asChild
would be essentially:
<a
href="https://example.com"
class="bg-neutral-a11"
role="button"
>
Visit Website
</a>
Our components use different Slot implementations based on platform:
- Web: Uses
@radix-ui/react-slot
for DOM elements - Native: Uses
@rn-primitives/slot
for React Native components
This allows the same API to work seamlessly across platforms while respecting platform-specific behavior.
Slot power:
- š Style inheritance - Your elements inherit DS3 styling
- š Behavior injection - DS3 behaviors transfer to your elements
- āæ Accessibility transfer - Accessibility attributes preserved
š ļø Development
# Install dependencies
pnpm i
# Watch and build
pnpm dev
# Production build
pnpm build
š¤ Contributing
We welcome contributions! Check out our Contributing Guidelines for detailed information on our development workflow, code standards, and how to submit changes.
š License
MIT