dynamic_ui_renderer 0.3.0
dynamic_ui_renderer: ^0.3.0 copied to clipboard
A Flutter package for rendering UI from JSON responses. Build dynamic forms, screens, and components from server-driven JSON.
dynamic_ui_renderer #
A powerful Flutter package for rendering UI dynamically from JSON responses. Build forms, screens, and components from server-driven JSON โ without requiring app updates.
Perfect for: Server-Driven UI (SDUI), Dynamic Forms, A/B Testing, CMS-driven UIs, and White-Label Apps
โจ Features #
๐ Network Fetching (v0.3.0) #
- โ Load UI from URL - Single-line API to fetch and render UI from any endpoint
- โ All HTTP Methods - GET, POST, PUT, PATCH, DELETE with custom headers and body
- โ Auto Retry - Exponential backoff with configurable max retries
- โ Smart Retry Logic - Never retries 4xx errors; retries 5xx automatically
- โ Typed Exceptions - Timeout, NoInternet, HTTP error, InvalidJSON, MaxRetries
- โ Custom Loading/Error UI - Replace defaults with your own widgets
- โ Retry Button - Built-in retry in the default error widget
๐ Complete Forms & Validation System #
- โ Dynamic Form Widget - Full-featured form container with validation
- โ 10+ Field Types - Text, Email, Password, Number, Phone, Dropdown, Checkbox, Date, Textarea, Radio
- โ Real-time Validation - Validate as users type with instant feedback
- โ Multi-Form Support - Handle multiple independent forms with unique IDs
- โ Form Callbacks - Global and per-form submission callbacks with form data
- โ Conditional Visibility - Show/hide fields based on other field values
- โ Form Reset - Complete form reset for all field types
โ 12+ Validation Rules #
| Rule | Description | Example |
|---|---|---|
required |
Field must have a value | {"type": "required"} |
email |
Valid email format | {"type": "email"} |
minLength |
Minimum character length | {"type": "minLength", "value": 8} |
maxLength |
Maximum character length | {"type": "maxLength", "value": 50} |
minValue |
Minimum numeric value | {"type": "minValue", "value": 18} |
maxValue |
Maximum numeric value | {"type": "maxValue", "value": 120} |
pattern |
Regex pattern matching | {"type": "pattern", "pattern": "^[A-Z]+$"} |
match |
Match another field's value | {"type": "match", "value": "password"} |
phone |
Valid phone number format | {"type": "phone"} |
url |
Valid URL format | {"type": "url"} |
date |
Valid date format | {"type": "date"} |
custom |
Custom validation logic | {"type": "custom", "customConfig": {...}} |
๐ฏ Complete Action System #
- โ Print - Debug logging with levels (info/warning/error)
- โ Dialog - Alert dialogs with custom titles and messages
- โ Snackbar - Toast notifications with action buttons
- โ
URL Launch - Open web links in browser (uses
url_launcher) - โ Bottom Sheet - Modal bottom sheets
- โ Navigation - Screen navigation with push/pop strategies
๐จ Core Widgets #
- โ Text - Full styling (size, weight, color, alignment)
- โ Container - Padding, margin, color, dimensions, border radius
- โ Button - Styled buttons with actions
- โ Column - Vertical layouts with alignment
- โ Row - Horizontal layouts with alignment
๐ ๏ธ Developer Experience #
- โ Type-safe JSON parsing - No runtime surprises
- โ Error handling - Graceful fallbacks with user-friendly messages
- โ Context propagation - Automatic for navigation and dialogs
- โ Extensible architecture - Easy to add custom widgets
- โ Well tested - 95%+ code coverage
- โ
Lightweight - Minimal dependencies (
http,url_launcher)
๐ฆ Installation #
Add the dependency to your pubspec.yaml:
dependencies:
dynamic_ui_renderer: ^0.3.0
Then run:
flutter pub get
Note: The package includes
httpfor network fetching andurl_launcherfor web URL support. No additional setup needed!
๐ Quick Start #
import 'package:flutter/material.dart';
import 'package:dynamic_ui_renderer/dynamic_ui_renderer.dart';
void main() {
// Register form callbacks (optional)
DynamicUIRenderer.registerFormCallback('login_form', (formId, formData) {
print('Login form submitted: $formData');
});
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Dynamic UI Demo')),
body: DynamicUIRenderer.fromJsonString('''
{
"type": "column",
"properties": {
"crossAxisAlignment": "stretch",
"padding": 16
},
"children": [
{
"type": "text",
"properties": {
"text": "Login Form",
"fontSize": 24,
"fontWeight": "bold",
"color": "#2196F3"
}
},
{
"type": "form",
"properties": {
"formId": "login_form",
"submitText": "Login",
"submitButtonColor": "#4CAF50"
},
"fields": [
{
"name": "email",
"type": "email",
"label": "Email",
"required": true,
"validations": [
{"type": "email", "message": "Invalid email"}
]
},
{
"name": "password",
"type": "password",
"label": "Password",
"required": true,
"validations": [
{"type": "minLength", "value": 6}
]
},
{
"name": "rememberMe",
"type": "checkbox",
"label": "Remember me"
}
]
}
]
}
''', context, formId: 'login_form'),
),
);
}
}
๐ Documentation #
๐ Form JSON Schema #
Form Widget
{
"type": "form",
"properties": {
"formId": "unique_form_id", // Optional: for multi-form support
"title": "Form Title", // Optional
"titleFontSize": 18, // Optional
"titleColor": "#1976D2", // Optional
"backgroundColor": "#FFFFFF", // Optional
"padding": 20, // Optional
"borderRadius": 12, // Optional
"elevation": 4, // Optional
"submitText": "Submit", // Optional: default "Submit"
"submitButtonColor": "#4CAF50", // Optional
"submitButtonTextColor": "#FFFFFF", // Optional
"submitButtonRadius": 8, // Optional
"submitButtonHeight": 48, // Optional
"showValidationMessage": true, // Optional: show error snackbar
"validationMessage": "Please fix errors" // Optional: custom error message
},
"fields": [] // Array of field configurations
}
๐ Field Types Reference #
Text Field
{
"name": "username",
"type": "text",
"label": "Username",
"hint": "Enter your username",
"placeholder": "johndoe",
"required": true,
"requiredMessage": "Username is required",
"order": 1,
"validations": [
{"type": "minLength", "value": 3, "message": "Minimum 3 characters"},
{"type": "maxLength", "value": 20, "message": "Maximum 20 characters"}
],
"uiProperties": {
"borderRadius": 8,
"filled": true,
"fillColor": "#F5F5F5",
"fontSize": 16,
"prefixIcon": "person",
"prefixIconColor": "#757575"
}
}
Email Field
{
"name": "email",
"type": "email",
"label": "Email Address",
"hint": "Enter your email",
"required": true,
"validations": [
{"type": "email", "message": "Invalid email format"}
],
"uiProperties": {
"prefixIcon": "email"
}
}
Password Field
{
"name": "password",
"type": "password",
"label": "Password",
"hint": "Create a strong password",
"required": true,
"validations": [
{"type": "minLength", "value": 8, "message": "Minimum 8 characters"},
{"type": "pattern", "pattern": "^(?=.*[A-Za-z])(?=.*\\d).{8,}$",
"message": "Must contain letter and number"}
],
"uiProperties": {
"prefixIcon": "lock"
}
}
Number Field
{
"name": "age",
"type": "number",
"label": "Age",
"hint": "Enter your age",
"validations": [
{"type": "minValue", "value": 18, "message": "Must be 18 or older"},
{"type": "maxValue", "value": 120, "message": "Invalid age"}
]
}
Phone Field
{
"name": "phone",
"type": "phone",
"label": "Phone Number",
"hint": "Enter your phone number",
"validations": [
{"type": "phone", "message": "Invalid phone number"}
],
"uiProperties": {
"prefixIcon": "phone"
}
}
Dropdown Field
{
"name": "country",
"type": "dropdown",
"label": "Country",
"hint": "Select your country",
"required": true,
"options": [
{"label": "United States", "value": "us", "icon": {"name": "home"}},
{"label": "India", "value": "in", "icon": {"name": "home"}},
{"label": "United Kingdom", "value": "uk", "disabled": true}
]
}
Checkbox Field
{
"name": "termsAccepted",
"type": "checkbox",
"label": "I accept the Terms and Conditions",
"required": true,
"requiredMessage": "You must accept the terms",
"uiProperties": {
"activeColor": "#4CAF50",
"checkColor": "#FFFFFF"
}
}
Date Field
{
"name": "birthDate",
"type": "date",
"label": "Birth Date",
"hint": "Select your birth date",
"uiProperties": {
"format": "dd/MM/yyyy",
"iconColor": "#1976D2"
}
}
Textarea Field
{
"name": "message",
"type": "textarea",
"label": "Message",
"hint": "Type your message",
"required": true,
"uiProperties": {
"minLines": 3,
"maxLines": 5
}
}
Radio Field
{
"name": "priority",
"type": "radio",
"label": "Priority",
"options": [
{"label": "Low", "value": "low"},
{"label": "Medium", "value": "medium"},
{"label": "High", "value": "high"}
]
}
๐ฌ Available Action Types #
| Type | Description | Required Parameters | Example |
|---|---|---|---|
print |
Print to console | message, level |
{"message": "Hello", "level": "info"} |
showDialog |
Show alert dialog | title, message, buttonText |
{"title": "Alert", "message": "Hello"} |
showSnackbar |
Show snackbar | message, duration, actionLabel |
{"message": "Saved!", "duration": 3} |
launchUrl |
Open URL in browser | url, mode |
{"url": "https://flutter.dev"} |
showBottomSheet |
Show modal bottom sheet | title, message, buttonText |
{"title": "Options"} |
navigate |
Navigate to route | route, type |
{"route": "/home", "type": "push"} |
๐ฏ Complete Examples #
๐ Multi-Form Demo #
// Register multiple form callbacks
DynamicUIRenderer.registerFormCallback('login_form', (formId, formData) {
print('Login: $formData');
});
DynamicUIRenderer.registerFormCallback('register_form', (formId, formData) {
print('Registration: $formData');
});
// Render forms with different IDs
Column(
children: [
DynamicUIRenderer.fromJsonString(loginFormJson, context, formId: 'login_form'),
DynamicUIRenderer.fromJsonString(registerFormJson, context, formId: 'register_form'),
],
);
๐ Dynamic Layout with Order Property #
{
"type": "form",
"fields": [
{"name": "field1", "type": "text", "label": "Field 1", "order": 3},
{"name": "field2", "type": "text", "label": "Field 2", "order": 1},
{"name": "field3", "type": "text", "label": "Field 3", "order": 2}
]
}
// Fields will render in order: field2, field3, field1
๐ Network Fetching (v0.3.0) #
// Simple GET โ one line
DynamicUIRenderer.fromNetwork(
'https://api.example.com/ui/dashboard',
context,
);
// POST with auth header and body
DynamicUIRenderer.fromNetwork(
'https://api.example.com/ui/generate',
context,
method: HttpMethod.post,
headers: {'Authorization': 'Bearer \$token'},
body: {'userId': '123', 'theme': 'dark'},
loadingWidget: const CircularProgressIndicator(),
errorWidget: (error) => Text('Failed: \$error'),
);
// Full control via NetworkRequest object
final request = NetworkRequest(
url: 'https://api.example.com/ui/profile',
method: HttpMethod.get,
headers: {'Authorization': 'Bearer \$token'},
timeout: const Duration(seconds: 15),
maxRetries: 5,
);
DynamicUIRenderer.fromNetworkWithRequest(request, context);
Expected JSON format from your server
Your API endpoint should return the same JSON schema that fromJsonString accepts:
{
"type": "column",
"properties": { "padding": 16 },
"children": [
{
"type": "text",
"properties": { "text": "Loaded from server!", "fontSize": 24 }
}
]
}
Exception types
| Exception | When thrown |
|---|---|
TimeoutException |
Request exceeded timeout duration |
NoInternetException |
No network connectivity |
HttpException |
Server returned non-2xx status |
InvalidJsonException |
Response body is not valid JSON |
MaxRetriesExceededException |
All retry attempts exhausted |
๐ฑ Complete Demo App #
Check out the /example folder for a complete Flutter app demonstrating all features:
cd example
flutter run
The example app includes:
- ๐ฏ Button Actions Demo - Test all 6 action types
- ๐ฑ Core Widgets Demo - Basic widgets showcase
- ๐จ Styling Properties Demo - Colors, fonts, padding, margins
- ๐ Layout Examples Demo - Different alignments and arrangements
- ๐ Multi-Form Demo - Three independent forms with real-time data display
- Registration Form with all field types
- Contact Form with dropdown and textarea
- Dynamic Layout Form with toggleable field order
- ๐ Network Loading Demo - Live interactive demo with 3 real HTTP scenarios
- Load UI from GitHub (real GET โ spinner โ rendered widget)
- Simulate Error (real 404 โ DefaultErrorWidget + working Retry)
- Simulate Timeout (1ms timeout โ TimeoutException)
- โ ๏ธ Error Handling Demo - Graceful fallbacks for unsupported widgets
๐ Architecture Overview #
URL โโโบ NetworkLoader โโโบ HttpClient โโโบ (retry + timeout)
โ
โผ
JSON โโโบ UIComponent (Model) โโโบ WidgetFactory โโโบ Flutter Widget
โ โ
Form Models Properties Parser
โ โ
FormController Action Handler
โ โ
Validation Navigation/Dialogs
The package follows a clean, modular architecture:
- Network Layer - Fetches JSON from URLs with retry, timeout, and error handling
- JSON Parsing - Converts JSON to type-safe models
- Form Models - Type-safe field and validation rule definitions
- FormController - Manages form state, validation, and submissions
- Widget Factory - Maps component types to Flutter widgets
- Property Parsers - Safely converts JSON values to Flutter types
- Action Handler - Executes user interactions
๐งช Testing #
# Run all tests
flutter test
# Run with coverage
flutter test --coverage
# Generate coverage report (requires lcov)
genhtml coverage/lcov.info -o coverage/html
# Then open coverage/html/index.html
๐ Package Statistics #
| Metric | Value |
|---|---|
| Latest Version | v0.3.0 |
| Published | April 2026 |
| License | MIT |
| Platforms | Android, iOS, Web, macOS, Linux, Windows |
| Dependencies | http, url_launcher |
| Field Types | 10+ |
| Validation Rules | 12+ |
| Test Coverage | 95%+ |
๐ค Contributing #
Contributions are welcome! Whether it's:
- ๐ Reporting bugs
- ๐ก Suggesting features
- ๐ Improving documentation
- ๐ง Submitting pull requests
Steps to contribute:
- Fork the repository
- Create your feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m "Add some amazing feature" - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
๐ License #
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments #
- Inspired by server-driven UI patterns at Airbnb, Lyft, and Prowork
- Built with โค๏ธ for the Flutter community
- Thanks to all contributors and users
๐ Support #
- ๐ง Email: webdevjash6@gmail.com
- ๐ Issues: GitHub Issues
- โญ Star: GitHub Repository
๐ฎ Roadmap #
| Version | Feature | Status |
|---|---|---|
| v0.2.1 | Forms & Validation | โ Done |
| v0.3.0 | Network Fetching | โ Done |
| v0.4.0 | Caching | โณ Next |
| v1.0.0 | Custom Widget Registry | ๐ฏ Planned |
| v1.1.0 | Theme Support | ๐ Planned |
If you find this package useful, please consider:
- โญ Starring the GitHub repository
- ๐ข Sharing it with others
- ๐ Reporting issues
- ๐ก Suggesting features
Made for Flutter Community with โค๏ธ by Jashwanth Gowda R