Flutter Remote UI
A production-ready Flutter package that enables fully JSON-driven, remote-configurable UIs. Designed for server-driven UI (SDUI) in apps that require instant updates, A/B testing, and dynamic content without app store releases.
Features
- Strict JSON Schema: Type-safe rendering with fail-soft error handling.
- Native Performance: Maps JSON directly to Flutter widgets (no WebViews).
- Core Widget Set: Column, Row, Stack, Text, Image, Button.
- Form System: Input binding, validation rules, and state management.
- Logic Engine: Conditional rendering and expressions (
${variable} > 0). - Extensible Registry: Register your own custom widgets easily.
- Aesthetics: Support for style properties like padding, margins, colors, and layouts.
Installation
Add this to your package's pubspec.yaml file:
dependencies:
flutter_remote_ui_kit: ^1.0.0
Quick Start
1. Initialize the Engine
In your main.dart, initialize the RemoteUI singleton with a registry. You can use
createDefaultRegistry() to get the standard set of widgets.
import 'package:flutter_remote_ui_kit/flutter_remote_ui_kit.dart';
void main() {
RemoteUI.init(
registry: createDefaultRegistry(),
// Optional: Add custom action handlers or logger
actionHandler: MyActionHandler(),
);
runApp(const MyApp());
}
2. Render a UI
Use RemoteUIRenderer to fetch and render the JSON. You can load from a network URL or provide the
data directly.
From Network:
class MyScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: RemoteUIRenderer.network(
url: 'https://api.myapp.com/screens/home.json',
placeholder: const Center(child: CircularProgressIndicator()),
errorBuilder: (e) => Center(child: Text('Failed to load: $e')),
),
);
}
}
From Data (Direct):
RemoteUIRenderer.data
(
data: RemoteWidgetData.fromJson(myJsonMap),
initialData: { "username": "JohnDoe" }, // Initial state variables
)
JSON Schema Example
A simple screen with a column, text, and a conditional button.
{
"type": "column",
"style": {
"padding": 16,
"backgroundColor": "#FFFFFF"
},
"children": [
{
"type": "text",
"props": {
"text": "Welcome, ${username}!",
"style": {
"fontSize": 24,
"fontWeight": "bold"
}
}
},
{
"type": "conditional",
"props": {
"condition": "${cartCount} > 0",
"true": {
"type": "button",
"props": {
"label": "Checkout Now"
},
"actions": {
"onTap": {
"type": "navigate",
"payload": {
"route": "/cart"
}
}
}
}
}
}
]
}
Supported Widgets
The default registry includes:
| Type | Description |
|---|---|
column |
Vertical layout (Flex) |
row |
Horizontal layout (Flex) |
stack |
Z-axis layout |
text |
Renders text with style properties |
image |
Renders network images |
button |
Native clickable button |
sized_box |
Spacer with width/height |
text_input |
Form input bound to state variables |
conditional |
Logic widget for rendering based on state |
Forms & State Binding
Widgets can bind to the local state controller using the bind property.
{
"type": "text_input",
"props": {
"bind": "email",
"labelText": "Email Address",
"validators": [
{
"rule": "required",
"message": "Required"
},
{
"rule": "regex",
"pattern": "^\\S+@\\S+\\.\\S+$",
"message": "Invalid Email"
}
]
}
}
Use ${variableName} syntax in text or condition strings to access these values.
Extensibility
You can register custom widgets to handle valid Flutter widgets that aren't in the core set.
// 1. Define the builder
Widget buildMyCustomWidget(BuildContext context, RemoteWidgetData data) {
return MyFancyWidget(
title: data.props['title'],
color: StyleUtils.parseColor(data.props['color']),
);
}
// 2. Register it
RemoteUI.registry.register
('my_fancy_widget
'
, buildMyCustomWidget);
Then use it in JSON:
{
"type": "my_fancy_widget",
"props": {
"title": "Hello",
"color": "#FF0000"
}
}
Contributing
Contributions are welcome! Please check out the example directory for a functional demo.
License
MIT
☕ Support the Project
If Flutter Remote UI has saved you development time or helped you ship faster, consider supporting the project.
This package is maintained in my free time, and your support helps:
Improve stability & performance
Add new widgets and features
Maintain long-term compatibility with Flutter updates