Migration from Flutter
Flutter developers face a common challenge: while Flutter excels at building beautiful mobile applications, its web support presents significant limitations for production use. Search engine crawlers struggle with Flutter web apps due to heavy reliance on canvas rendering and JavaScript, making it difficult for Google and other search engines to index content properly. Dynamic content, meta tags, and structured data are nearly impossible to implement in a way that satisfies modern SEO requirements.
When Flutter developers transition to React for web development, they encounter an entirely different paradigm. React's component model, JSX syntax, and CSS-based styling represent a fundamental shift from Flutter's declarative widget tree and built-in theming system. This learning curve can be steep, especially when managing layouts without Flutter's intuitive primitives like Column, Row, Stack, and Container.
Layr bridges this gap. It brings Flutter's layout philosophy to React, allowing you to build web applications with the same mental model you've developed in Flutter, while maintaining full SEO compatibility, accessibility, and web-native performance.
1. Core Concept Mapping
Layr provides direct equivalents for Flutter's most commonly used layout widgets:
Flutter WidgetLayr ComponentNotes
ContainerContainerIdentical API for decoration, padding, margin
RowRowSame alignment system with MainAxisAlignment
ColumnColumnSame alignment system with CrossAxisAlignment
StackStackIdentical layering and positioning behaviour
PositionedPositionedSame props: top, left, right, bottom
SizedBoxSizedBoxFixed width/height constraints
PaddingPaddingLightweight padding wrapper
CenterCentreCentres children (British spelling supported)
ExpandedNot made yetUse CSS flex: 1 instead
FlexibleNot made yetUse CSS flexbox properties
2. API Differences
2a. Decoration API
Flutter's BoxDecoration is fully supported with near-identical syntax. Flutter:

Dart

Container(
width: 200,
height: 200,
decoration: BoxDecoration(
color: Color(0xFFEB1660),
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black26,
offset: Offset(0, 4),
blurRadius: 12,
),
],
),
)
Layr:

Tsx

Preview

NOTE: Previews are not depiction of actual website output.
Key changes:
• Colours use web formats (#hex, rgb(), rgba()) • Offset becomes a { dx, dy } object • BorderRadius.circular() becomes a number or helper function
2b. EdgeInsets API
Flutter's EdgeInsets factory constructors are available. Flutter:

Dart

Container(
padding: EdgeInsets.all(16),
margin: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Text('Hello'),
)
Layr:

Tsx

Preview

NOTE: Previews are not depiction of actual website output.
Alternative (object syntax):

Tsx

<Container
padding={{ all: 16 }}
margin={{ horizontal: 20, vertical: 10 }}
>
Hello
</Container>
Alternative (shorthand):

Tsx

<Container
padding={16}
paddingHorizontal={20}
marginVertical={10}
>
Hello
</Container>
2c. Alignment System
Flutter's alignment enums work identically. Flutter:

Dart

Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Item 1'),
Text('Item 2'),
],
)
Layr:

Tsx

Preview

NOTE: Previews are not depiction of actual website output.
Available values:
MainAxisAlignment: start, center, end, spaceBetween, spaceAround, spaceEvenlyCrossAxisAlignment: start, center, end, stretch, baseline
2d. Stack & Positioned
Flutter's Stack behavior is preserved. Flutter:

Dart

Stack(
alignment: Alignment.center,
children: [
Container(width: 200, height: 200, color: Colors.blue),
Positioned(
top: 10,
right: 10,
child: Container(width: 50, height: 50, color: Colors.red),
),
],
)
Layr:

Tsx

Preview

NOTE: Previews are not depiction of actual website output.
Key points:
Stack requires height and width values • Children are painted in order (first = bottom layer) • Positioned must be a direct child of Stack • Use PositionedFill as shorthand for full fill
2e. Spacing
Flutter requires SizedBox or Padding for spacing. Layr provides a spacing prop Flutter:

Dart

Column(
children: [
Text('Item 1'),
SizedBox(height: 16),
Text('Item 2'),
SizedBox(height: 16),
Text('Item 3'),
],
)
Layr (cleaner):

Tsx

Preview

NOTE: Previews are not depiction of actual website output.
Both Row and Column support spacing natively.
3. What's Different
3a. Children vs Child
React uses children prop for all child content (no distinction between single and multiple children): Flutter:

Dart

Container(
child: Text('Single child'),
)
Layr:

Tsx

<Container>Single child</Container>
3b. Text Widgets
Flutter's Text widget is replaced by semantic HTML elements like span, p, and h1. Flutter:

Dart

Text(
'Hello World',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.red,
),
)
Layr:

Tsx

<span style={{
fontSize: 16,
fontWeight: 'bold',
color: 'red',
}}>
Hello World
</span>
3c. No Built-In Theme System
Flutter's Theme.of(context) doesn't exist. Use CSS variables, React Context, or a library like styled-components.

Tsx

// Define theme in CSS
:root {
--primary-color: #eb1660;
--spacing-unit: 8px;
}
// Use in Layr
<Container color="var(--primary-color)" padding={16} />
3d. Events
Flutter gestures map to standard DOM events. onTap is also supported as an alias. Flutter:

Dart

GestureDetector(
onTap: () => print('Tapped'),
child: Container(child: Text('Click me')),
)
Layr:

Tsx

<Container onClick={() => console.log('Tapped')}>
Click me
</Container>
3e. State Management
Flutter's setState becomes React's useState. Flutter:

Dart

class Counter extends StatefulWidget {
@override
_CounterState createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int count = 0;
void increment() {
setState(() => count++);
}
@override
Widget build(BuildContext context) {
return Text('$count');
}
}
Layr:

Tsx

import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<Container onTap={() => setCount(count + 1)}>
{count}
</Container>
);
}
4. Migration Examples
4a. Card Component
Flutter:

Dart

Container(
width: 320,
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 12,
offset: Offset(0, 4),
),
],
),
child: Column(
spacing: 16,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Card Title', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
Text('This is a card description.'),
],
),
)
Layr:

Tsx

Preview

NOTE: Previews are not depiction of actual website output.
4b. Pro Plan Component
Flutter:

Dart

Stack(
clipBehavior: Clip.none,
children: [
Container(
width: 280,
padding: EdgeInsets.all(32),
decoration: BoxDecoration(
color: Color(0x1d0d1d),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Color(0x1A000000),
blurRadius: 24,
offset: Offset(0, 8),
),
],
border: Border.all(
color: Color(0xFFEB1660),
width: 2,
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
spacing: 20,
children: [
Text(
'Pro Plan',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 4,
children: [
Text(
'\$',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
),
),
Text(
'49',
style: TextStyle(
fontSize: 48,
fontWeight: FontWeight.bold,
color: Color(0xFFEB1660),
),
),
Text(
'/mo',
style: TextStyle(
fontSize: 16,
color: Colors.grey,
),
),
],
),
Column(
spacing: 12,
children: [
FeatureItem(text: 'Unlimited projects'),
FeatureItem(text: 'Priority support'),
FeatureItem(text: 'Advanced analytics'),
],
),
],
),
),
Positioned(
top: -12,
right: 20,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 6),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFFEB1660), Color(0xFFFF6B9D)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(99),
boxShadow: [
BoxShadow(
color: Color(0x40EB1660),
blurRadius: 8,
offset: Offset(0, 2),
),
],
),
child: Text(
'POPULAR',
style: TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.bold,
letterSpacing: 0.5,
),
),
),
),
],
)
Layr:

Tsx

Preview

NOTE: Previews are not depiction of actual website output.
5. Things That Don't Exist (Yet)
Expanded / Flexible — Use CSS flex: 1ListView / GridView — Use standard HTML scrolling or a virtualization library • AppBar / Scaffold — Build your own with Container, Row, Column • Navigator / Routes — Use React Router or Next.js routing • TextField / Form — Use native HTML <input> and form elements • IconButton / ElevatedButton — Build your own or use a UI library
6. Common Pitfalls
6a. Forgetting JSX Syntax
Flutter uses commas between properties. React/JSX does not:

Tsx

// ❌ Wrong
<Container width={200}, height={100}, />
// ✅ Correct
<Container width={200} height={100} />
6b. Color Format
Flutter uses Color(0xFFRRGGBB). Web uses strings:

Tsx

)
// ❌ Wrong
<Container color={0xFFEB1660} />
// ✅ Correct
<Container color="#eb1660" />
6c. Trying to Use StatefulWidget
React doesn't have StatefulWidget. Use functional components with hooks:

Tsx

// ❌ Don't try this
class MyComponent extends StatefulWidget { }
// ✅ Use this
function MyComponent() {
const [state, setState] = useState(initialValue);
return <Container />;
}
7. Quick Reference
7a. Container
FlutterLayr
width: 200width={200}
height: 100height={100}
padding: EdgeInsets.all(16)padding={16} or padding={{ all: 16 }}
margin: EdgeInsets.only(top: 10)margin={{ top: 10 }}
color: Colors.redcolor="#ff0000"
decoration: BoxDecoration(...)decoration={{ ... }}
7b. Row / Column
FlutterLayr
mainAxisAlignment: MainAxisAlignment.centermainAxisAlignment={MainAxisAlignment.center}
crossAxisAlignment: CrossAxisAlignment.startcrossAxisAlignment={CrossAxisAlignment.start}
mainAxisSize: MainAxisSize.minmainAxisSize={MainAxisSize.min}
No built-in spacingspacing={16}
7c. Stack / Positioned
FlutterLayr
Positioned(top: 10, left: 10, child: ...)<Positioned top={10} left={10}>...</Positioned>
Positioned.fill(child: ...)<PositionedFill>...</PositionedFill>
Stack(alignment: Alignment.center, ...)<Stack alignment="center">...</Stack>
8. Next Steps
TypeScript Setup — Configure types for optimal autocomplete • Container — Deep dive into decoration and constraints