A SwiftUI-inspired declarative UI framework for React Native
npm install @1dance/flexA SwiftUI-inspired declarative UI framework for React Native. Build beautiful, type-safe mobile apps with a familiar, chainable API.



- Installation
- Quick Start
- Core Concepts
- DView Component
- Modifier System
- Style Builder (style)
- Swift Modifiers (swift)
- Layout Components
- Views
- Styling
- State Management
- Examples
- API Reference
---
``bash`
npm install @1dance/flexor
yarn add @1dance/flex
`bash`
npm install react react-native
---
`tsx
import React from 'react';
import {
DView,
VStack,
Text,
Button,
Color,
Font,
modifier,
style,
useStateValue,
EnvironmentProvider,
HorizontalAlignment,
} from '@1dance/flex';
export default function App() {
const [count, countBinding] = useStateValue(0);
return (
.flex(1)
.padding(20)
.background(Color.background.toString())
)}>
{Text('Hello, Flex!')
.font(Font.largeTitle)
.foregroundColor(Color.blue)
.bold()
.render()}
{Text(Count: ${count})
.font(Font.title)
.render()}
title="Increment"
action={() => countBinding.set(count + 1)}
style="borderedProminent"
/>
);
}
`
---
DView is the foundational view component that replaces React Native's View. It uses modifiers instead of the style prop.
`tsx
import { DView, modifier, style } from '@1dance/flex';
.flex(1)
.padding(20)
.background('#ffffff')
)}>
{/ children /}
`
The modifier system provides a chainable API combining style() for layout properties and swift() for interactions/accessibility.
`tsx
import { modifier, style, swift } from '@1dance/flex';
.flex(1)
.padding(20)
.background('#fff')
.cornerRadius(12)
)
.swift(swift() // SwiftUI-like modifiers
.onTapGesture(() => console.log('Tapped!'))
.accessibilityLabel('My View')
)
}>
`
The style() builder handles all React Native ViewStyle properties:
`tsx
import { style } from '@1dance/flex';
const myStyle = style()
// Flexbox
.flex(1)
.flexDirection('row')
.justifyContent('space-between')
.alignItems('center')
// Sizing
.width(200)
.height(100)
.size(50) // width & height
.aspectRatio(16/9)
// Spacing
.padding(20)
.paddingHorizontal(16)
.margin(10)
.gap(8)
// Position
.position('absolute')
.top(0).right(0).bottom(0).left(0)
.zIndex(10)
// Background & Border
.background('#007AFF')
.cornerRadius(12)
.border('#ccc', 1)
// Shadow
.shadow({ radius: 8, x: 0, y: 4, opacity: 0.2 })
// Visibility
.opacity(0.9)
.overflow('hidden');
`
#### Preset Styles
`tsx
import { Styles } from '@1dance/flex';
`
The swift() builder handles interactions, transforms, and accessibility:
`tsx
import { swift, Font, Color } from '@1dance/flex';
const mySwiftModifiers = swift()
// Typography
.font(Font.title)
.bold()
.foregroundColor(Color.blue)
// Transforms
.rotation(45)
.scale(1.2)
.offset(10, 20)
// Clipping
.clipCircle()
.clipRoundedRect(12)
// Gestures
.onTapGesture(() => console.log('Tapped'))
.onLongPressGesture(() => console.log('Long pressed'))
.disabled(false)
// Accessibility
.accessibilityLabel('My Button')
.accessibilityRole('button');
`
---
Vertical stack layout. Default alignment is Leading (left-aligned).
`tsx
import { VStack, HorizontalAlignment } from '@1dance/flex';
// Left-aligned (default)
{Text('First').render()}
{Text('Second').render()}
// Centered
{Text('Centered').render()}
`
Horizontal stack layout.
`tsx
import { HStack, Spacer } from '@1dance/flex';
{Text('Left').render()}
{Text('Right').render()}
`
Overlapping stack layout.
`tsx
import { ZStack, Alignments } from '@1dance/flex';
{Image('background.jpg').render()}
{Text('Overlay').render()}
`
Flexible space that expands to fill available space.
`tsx`
{Text('Left').render()}
{Text('Right').render()}
---
Declarative text with chainable modifiers.
`tsx
import { Text, Font, Color } from '@1dance/flex';
{Text('Hello World')
.font(Font.title)
.foregroundColor(Color.blue)
.bold()
.italic()
.underline()
.lineLimit(2)
.render()}
`
Declarative image with modifiers.
`tsx
import { Image } from '@1dance/flex';
{Image('https://example.com/image.jpg')
.resizable()
.aspectRatio(16/9)
.frame({ width: 200, height: 112 })
.cornerRadius(8)
.render()}
`
Interactive button with multiple styles.
`tsx
import { Button } from '@1dance/flex';
Switch control.
`tsx
import { Toggle, useStateValue } from '@1dance/flex';
const [isOn, binding] = useStateValue(false);
onToggle={(value) => binding.set(value)}
label="Enable Feature"
/>
`
Visual separator line.
`tsx
import { Divider } from '@1dance/flex';
`
---
Semantic colors that adapt to light/dark mode.
`tsx
import { Color } from '@1dance/flex';
// Semantic colors
Color.label // Primary text
Color.secondaryLabel // Secondary text
Color.background // Primary background
Color.separator // Divider lines
// System colors
Color.blue
Color.green
Color.red
Color.orange
// Custom colors
Color.hex('#FF5733')
Color.rgb(255, 87, 51)
// With opacity
Color.blue.opacity(0.5)
`
Type-safe font definitions.
`tsx
import { Font } from '@1dance/flex';
Font.largeTitle // 34pt
Font.title // 28pt
Font.title2 // 22pt
Font.headline // 17pt, semibold
Font.body // 17pt
Font.caption // 12pt
// Custom font
Font.system(20, 'bold')
`
---
React hook for state with binding support.
`tsx
import { useStateValue } from '@1dance/flex';
function Counter() {
const [count, countBinding] = useStateValue(0);
return (
{Text(Count: ${count}).render()}
action={() => countBinding.set(count + 1)}
/>
);
}
`
---
`tsx
import React from 'react';
import {
DView,
Text,
VStack,
Color,
Font,
modifier,
style,
swift,
HorizontalAlignment,
} from '@1dance/flex';
export function HelloWorldExample() {
return (
.flex(1)
.padding(20)
)}>
{Text('Hello, Flex!')
.font(Font.largeTitle)
.foregroundColor(Color.blue)
.bold()
.render()}
{Text('Build beautiful React Native apps')
.font(Font.title2)
.foregroundColor(Color.secondaryLabel)
.render()}
{Text('with a SwiftUI-inspired API')
.font(Font.body)
.italic()
.foregroundColor(Color.gray)
.render()}
.swift(swift()
.onTapGesture(() => console.log('Button tapped!'))
.accessibilityLabel('Welcome button')
.accessibilityRole('button')
)
}>
{Text('Get Started')
.font(Font.headline)
.foregroundColor(Color.white)
.render()}
);
}
`
`tsx
import React from 'react';
import {
DView,
Text,
Button,
VStack,
HStack,
Color,
Font,
modifier,
style,
useStateValue,
HorizontalAlignment,
} from '@1dance/flex';
export function CounterExample() {
const [count, countBinding] = useStateValue(0);
return (
.flex(1)
.padding(20)
)}>
{Text('Counter').font(Font.title).bold().render()}
{Text(${count})
.font(Font.system(64))
.foregroundColor(count >= 0 ? Color.blue : Color.red)
.render()}
);
}
`
`tsx
import React from 'react';
import { ScrollView, Image as RNImage } from 'react-native';
import {
DView,
Text,
Button,
VStack,
HStack,
Color,
Font,
modifier,
style,
swift,
useStateValue,
HorizontalAlignment,
} from '@1dance/flex';
export function ProfileCardExample() {
const [isFollowing, followingBinding] = useStateValue(false);
return (
style()
.background('#F2F2F7')
.cornerRadius(16)
.padding(20)
.alignItems('center')
.shadow({ radius: 8, y: 4, opacity: 0.1 })
)
.swift(swift().accessibilityLabel('Profile card for Sarah Johnson'))
}>
{/ Avatar /}
.swift(swift().clipCircle())
}>
style={{ width: '100%', height: '100%' }}
/>
{Text('Sarah Johnson').font(Font.title2).bold().render()}
{Text('@sarahj')
.font(Font.subheadline)
.foregroundColor(Color.secondaryLabel)
.render()}
{/ Stats /}
{Text('1.2K').font(Font.headline).bold().render()}
{Text('Posts').font(Font.caption).foregroundColor(Color.secondaryLabel).render()}
{Text('45.8K').font(Font.headline).bold().render()}
{Text('Followers').font(Font.caption).foregroundColor(Color.secondaryLabel).render()}
action={() => followingBinding.set(!isFollowing)}
style={isFollowing ? 'bordered' : 'borderedProminent'}
/>
);
}
`
`tsx
import React from 'react';
import { ScrollView, TextInput, Switch, Text as RNText } from 'react-native';
import {
DView,
Text,
Button,
HStack,
Color,
Font,
modifier,
style,
useStateValue,
} from '@1dance/flex';
export function FormExample() {
const [form, formBinding] = useStateValue({
name: '',
email: '',
agreedToTerms: false,
});
const [errors, errorsBinding] = useStateValue
const validate = () => {
const newErrors: Record
if (!form.name.trim()) newErrors.name = 'Name is required';
if (!form.email.trim()) newErrors.email = 'Email is required';
if (!form.agreedToTerms) newErrors.terms = 'You must agree';
errorsBinding.set(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = () => {
if (validate()) {
console.log('Form submitted:', form);
}
};
return (
{Text('Sign Up').font(Font.title).bold().render()}
{/ Name Field /}
{Text('Name').font(Font.headline).render()}
onChangeText={(name) => formBinding.set({ ...form, name })}
placeholder="Enter your name"
style={{
padding: 16,
backgroundColor: '#F5F5F5',
borderRadius: 10,
fontSize: 16,
}}
/>
{errors.name && (
)}
{/ Email Field /}
{Text('Email').font(Font.headline).render()}
onChangeText={(email) => formBinding.set({ ...form, email })}
placeholder="Enter your email"
keyboardType="email-address"
style={{
padding: 16,
backgroundColor: '#F5F5F5',
borderRadius: 10,
fontSize: 16,
}}
/>
{errors.email && (
)}
{/ Terms Toggle /}
{Text('I agree to the Terms').font(Font.body).render()}
onValueChange={(agreedToTerms) => formBinding.set({ ...form, agreedToTerms })}
/>
action={handleSubmit}
style="borderedProminent"
/>
);
}
`
---
| Component | Description |
|-----------|-------------|
| DView | Base view with modifier support |VStack
| | Vertical stack (default: left-aligned) |HStack
| | Horizontal stack |ZStack
| | Overlapping stack |Spacer
| | Flexible space |Divider
| | Visual separator |Button
| | Interactive button |Toggle
| | Switch control |
| View | Description |
|------|-------------|
| Text(string) | Text with chainable modifiers |Image(source)
| | Image with chainable modifiers |
| Builder | Description |
|---------|-------------|
| modifier() | Creates ModifierBuilder |style()
| | Creates DStyleBuilder for ViewStyle |swift()
| | Creates DSwiftBuilder for interactions |
| Hook | Description |
|------|-------------|
| useStateValue(initial) | State with binding |useEnvironment()
| | Environment access |useColorSchemeValue()` | Current color scheme |
|
---
MIT © 1Dance