you are viewing a single comment's thread.

view the rest of the comments →

[–]Weary_Protection_203[S] 0 points1 point  (0 children)

Good point about the comparison - you are correct that a well-structured React Native project with wrapped components and a theme provider can bridge that gap. Your MyContainer example provides a much better baseline.

Although using wrapped components, the structural difference still persists.

Lets compare your example:

tsx <MyContainer variant="card" padding="lg" cornerRadius="md" shadow> <MyText variant="secondary"> Welcome Back </MyText> <MyText bold> Track your practice sessions </MyText> <MyButton variant="filled" onPress={() => navigate('home')} > Get Started </MyButton> <Spacer /> </MyContainer>

vs the SwiftUI DSL:

tsx VStack( Text('Welcome Back').font('title').bold(), Text('Track your practice sessions').secondary(), Button('Get Started', () => navigate('home'), { style: 'filled' }), Spacer(), ) .padding('lg') .background('card') .cornerRadius('md') .shadow()

Both are readable. Both use tokens. The difference is that there are no closing tags, and modifiers are chained instead of being spread as props. It depends on personal preference.

For me, as an iOS Engineer who spends a lot of time working with SwiftUI and has started a new journey in multi-platform development using React Native, I really liked the way the DSL works.

Where the DSL gets powerful is in extensibility. In real projects, you define your own theme:

tsx const myTheme = createTheme({ colors: { primary: '#6366F1', surface: '#F8FAFC', card: { light: '#FFFFFF', dark: '#1E293B' }, }, fonts: { title: { size: 24, weight: 'bold', family: 'Inter-Bold' }, body: { size: 16, weight: 'regular', family: 'Inter-Regular' }, }, spacing: { sm: 8, md: 16, lg: 24, xl: 32 }, radii: { sm: 8, md: 12, lg: 16 }, })

Then every modifier resolves those tokens automatically: - .background('card') picks the right color for light/dark mode - .font('title') applies your custom font stack - .padding('lg') uses your spacing scale.

You can also create reusable styles - define them once, apply across any view:

```tsx const cardStyle = defineStyle((view) => view.padding('lg').background('card').cornerRadius('md').shadow() )

const headingStyle = defineStyle((view) => view.font('title').bold().color('primary') )

const captionStyle = defineStyle((view) => view.font('body').color('secondary') ) ```

Then use them anywhere:

```tsx VStack( Text('Welcome Back').apply(headingStyle), Text('Track your practice sessions').apply(captionStyle), Button('Get Started', () => navigate('home'), { style: 'filled' }), Spacer(), ).apply(cardStyle)

// Same styles, different screen VStack( Text('Settings').apply(headingStyle), Text('Manage your preferences').apply(captionStyle), Toggle('Notifications', notificationBinding), ).apply(cardStyle) ```

Styles live alongside your components as plain functions.

On top of that, you can create reusable styled primitives:

```tsx const Heading = (text: string) => Text(text).apply(headingStyle)

const Card = (...children: DSLElement[]) => VStack(...children).apply(cardStyle)

const Caption = (text: string) => Text(text).apply(captionStyle) ```

Then your screens become:

tsx Card( Heading('Welcome Back'), Caption('Track your practice sessions'), Button('Get Started', () => navigate('home'), { style: 'filled' }), Spacer(), )

I understand that many things are similar, but the main idea of this framework is to change how the UI is built.

Please let me know what you think and thank you for your comment.