QuicUI - Server-Driven UI Framework for Flutter

Pub Version Flutter License Build Status Architecture

QuicUI is a powerful Server-Driven UI (SDUI) framework for Flutter that enables you to build, update, and deliver dynamic user interfaces without redeploying your app. Define your UI as JSON and render it natively at runtime. Backend is fully optional - works standalone with local data, or integrates with any cloud backend via plugins.

πŸš€ Features

  • Instant Updates: Ship UI changes without App Store/Play Store approval
  • JSON-Driven: Define widgets in JSON, render natively in Flutter
  • Standalone Usage: Works with local JSON data - no backend required
  • Backend Optional: Integrate with Supabase, Firebase, REST API, or custom backends
  • Real-Time Sync: Live UI updates with minimal latency (when backend is available)
  • Dynamic Navigation: Control routes from the backend or locally
  • Form Management: Server-side or local forms with built-in validation
  • Dynamic Theming: Update branding and styles in real-time
  • Offline-First: Lightning-fast local database (ObjectBox) for offline apps
  • Extensible: Custom widgets, actions, and native integrations
  • Cross-Platform: iOS, Android, Web, Windows, macOS, Linux

πŸ“¦ What's New

v1.0.4 (October 30, 2025) - Callback Action System ✨ NEW

  • βœ… Generic callback action system (navigate, setState, apiCall, custom)
  • βœ… JSON-driven interactive flows without Dart code
  • βœ… Action chaining with success/error handling
  • βœ… Variable binding with ${variable_name} syntax
  • βœ… 29 comprehensive unit tests (100% passing)
  • βœ… 4,500+ lines of complete documentation
  • βœ… 15 working JSON examples (login, registration, CRUD)
  • βœ… Custom handler registry for app-specific logic
  • βœ… Built-in state management for interactive UIs

v1.0.1 (October 30, 2025) - Production Release ✨

  • βœ… Backend-agnostic plugin architecture
  • βœ… 70+ pre-built widgets fully functional
  • βœ… BLoC state management complete
  • βœ… Offline-first architecture with sync
  • βœ… Real-time UI sync support
  • βœ… ObjectBox local persistence
  • βœ… Comprehensive backend integration guides
  • βœ… 5 complete example applications
  • βœ… 11,000+ lines of documentation
  • βœ… 267/267 tests passing (100%)
  • βœ… Published to pub.dev

🎯 Quick Start

Installation

flutter pub add quicui

Minimal Setup (No Backend)

import 'package:quicui/quicui.dart';

void main() {
  runApp(QuicUIApp(home: MyApp()));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Render local JSON without any backend
    final jsonData = {
      'type': 'column',
      'properties': {'mainAxisAlignment': 'center'},
      'children': [
        {
          'type': 'text',
          'properties': {'text': 'Hello from Local JSON!', 'fontSize': 24}
        }
      ]
    };
    
    final screen = Screen.fromJson(jsonData);
    return UIRenderer.render(screen);
  }
}

πŸ“š Documentation

Getting Started

Backend Integration

Examples & Patterns

Technical Documentation

Example Applications

See /example folder for:

  • Counter App - Simple state management
  • Form App - Input handling and validation
  • Todo App - CRUD operations
  • Offline Sync App - Offline-first synchronization
  • Dashboard App - Complex layouts and theming

πŸ”Œ Official Plugins

QuicUI supports backend integration through official plugins. Mix and match plugins based on your needs:

QuicUI Supabase

Complete Supabase backend integration with real-time synchronization and offline-first architecture.

Features:

  • Real-time UI updates via WebSocket
  • Offline-first with automatic sync
  • Screen management and search
  • Conflict resolution
  • PostgreSQL database integration

Installation:

dependencies:
  quicui: ^1.0.2
  quicui_supabase: ^2.0.1

Usage:

import 'package:quicui_supabase/quicui_supabase.dart';

final dataSource = SupabaseDataSource(
  'https://your-project.supabase.co',
  'your-anon-key',
);
await QuicUIService().initializeWithDataSource(dataSource);

πŸ“– View Supabase Plugin Documentation


πŸ—οΈ Architecture Overview

Layered Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Presentation Layer (UI)   β”‚
β”‚  Widgets, Factory, Renderingβ”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Business Logic Layer        β”‚
β”‚ State, Forms, Actions       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Data Layer                β”‚
β”‚ API, Database, Cache        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Core Components

Component Purpose
Widget Factory Convert JSON to Flutter widgets
JSON Parser Parse and validate JSON schemas
State Manager Centralized reactive state
Action Executor Handle navigation, API, events
Form System Build & validate forms server-side
Local DB (ObjectBox) Fast, persistent local storage
Theme Manager Dynamic runtime theming
Sync Manager Offline-first sync strategy

🎨 Supported Widgets

Layout Widgets

  • Container, Column, Row, Stack, Center
  • Scaffold, AppBar, BottomNav, Drawer
  • ListView, GridView, SingleChildScrollView

Input Widgets

  • TextField, Checkbox, Radio, DropDown
  • Switch, DatePicker, FilePicker

Display Widgets

  • Text, Image, Icon, Badge, Chip
  • Card, Dialog, SnackBar

Advanced Widgets

  • Conditional (if/else)
  • Loop (dynamic lists)
  • Form (with validation)
  • Custom (extensible)

🎯 Interactive Callbacks System

Build dynamic, responsive UIs without writing Dart code! Define interactive workflows as JSON - the callback system handles everything from button taps to API calls to state management.

The 4 Generic Actions

Transform any static UI into an interactive app with these 4 reusable actions:

Action Purpose Example
navigate Move between screens Navigate to login, home, profile
setState Update UI state dynamically Toggle loading, show/hide elements
apiCall Make HTTP requests Fetch data, submit forms, authenticate
custom Execute app-specific logic Email validation, calculations, business logic

Quick Example: Login Screen

{
  "id": "button_login",
  "type": "ElevatedButton",
  "properties": {"label": "Login"},
  "actions": [
    {
      "action": "setState",
      "updates": {"isLoading": true}
    },
    {
      "action": "apiCall",
      "method": "POST",
      "endpoint": "/api/auth/login",
      "body": {
        "email": "${email_input}",
        "password": "${password_input}"
      },
      "onSuccess": {
        "action": "navigate",
        "screen": "home",
        "replace": true
      },
      "onError": {
        "action": "setState",
        "updates": {"error": "Login failed"}
      }
    },
    {
      "action": "setState",
      "updates": {"isLoading": false}
    }
  ]
}

Key Features

βœ… Action Chaining - Execute actions sequentially with success/error handling βœ… Variable Binding - Reference form inputs with ${variable_name} βœ… Event Triggers - onPressed, onTap, onLongTap, onChanged, onSubmitted βœ… State Management - Update UI state on-the-fly βœ… Custom Handlers - Register custom validation and business logic functions βœ… Error Handling - Built-in error callbacks with automatic retry βœ… Loading States - Show/hide loading indicators automatically

Complete Examples

How to Use

Step 1: Configure Base URL

void main() {
  ApiConfig.baseUrl = 'https://your-api.com';
  runApp(QuicUI());
}

Step 2: Use in JSON

{
  "action": "apiCall",
  "method": "POST",
  "endpoint": "/api/auth/login",
  "body": {"email": "${email}", "password": "${password}"}
}

Step 3: Optional - Add Custom Handlers

CallbackRegistry.register('validateEmail', (context, params) async {
  final email = params['email'] as String;
  if (!email.contains('@')) throw Exception('Invalid email');
  return {'valid': true};
});

Documentation

πŸ“– Complete Callback Guide - 4,500+ lines with:

  • All 4 actions with real code examples
  • 15 complete JSON examples
  • Step-by-step tutorials
  • Configuration guide
  • Advanced patterns
  • Testing examples

πŸ“ JSON Schema Example

About the ID Field

The id field in widgets is completely optional:

  • When to use: When you need to reference the widget from code (testing, state binding, or programmatic updates)
  • When to skip: For most widgets - just define type and properties
{
  "type": "text",
  "properties": {"text": "Hello"}
}

This minimal example works perfectly! Add id only if needed:

{
  "id": "greeting_text",
  "type": "text",
  "properties": {"text": "Hello"}
}

Simple Screen

{
  "type": "scaffold",
  "appBar": {
    "type": "appbar",
    "title": "Welcome"
  },
  "body": {
    "type": "column",
    "properties": {"padding": "16"},
    "children": [
      {
        "type": "text",
        "properties": {
          "text": "Hello QuicUI",
          "fontSize": 24,
          "fontWeight": "bold"
        }
      },
      {
        "type": "button",
        "properties": {"label": "Click Me"},
        "events": {
          "onPressed": {
            "action": "navigate",
            "screen": "detail_screen"
          }
        }
      }
    ]
  }
}

Note: All fields except type and properties are optional. The id field is optional and only needed if you want to reference the widget programmatically.

Counter App with Scaffold

{
  "type": "scaffold",
  "appBar": {
    "type": "appBar",
    "title": "Counter App",
    "backgroundColor": "#1976D2"
  },
  "body": {
    "type": "center",
    "child": {
      "type": "column",
      "mainAxisAlignment": "center",
      "crossAxisAlignment": "center",
      "children": [
        {
          "type": "text",
          "properties": {
            "text": "You have pushed the button this many times:",
            "fontSize": 16
          }
        },
        {
          "type": "sizedBox",
          "properties": {"height": 16}
        },
        {
          "type": "container",
          "properties": {
            "padding": "24",
            "decoration": {
              "color": "#E3F2FD",
              "borderRadius": "12"
            }
          },
          "child": {
            "type": "text",
            "properties": {
              "text": "42",
              "fontSize": 72,
              "fontWeight": "bold",
              "color": "#1976D2"
            }
          }
        },
        {
          "type": "sizedBox",
          "properties": {"height": 32}
        },
        {
          "type": "row",
          "mainAxisAlignment": "center",
          "children": [
            {
              "type": "elevatedButton",
              "properties": {
                "label": "βˆ’",
                "backgroundColor": "#F44336"
              }
            },
            {
              "type": "sizedBox",
              "properties": {"width": 16}
            },
            {
              "type": "elevatedButton",
              "properties": {
                "label": "+",
                "backgroundColor": "#4CAF50"
              }
            }
          ]
        }
      ]
    }
  },
  "floatingActionButton": {
    "type": "floatingActionButton",
    "icon": "Icons.add",
    "tooltip": "Increment"
  }
}

See Scaffold Counter App Example for complete implementation with state management.

Form with Validation

{
  "type": "form",
  "formId": "contact_form",
  "fields": [
    {
      "type": "textfield",
      "fieldName": "name",
      "label": "Full Name",
      "validators": [
        {"type": "required", "message": "Name is required"},
        {"type": "minLength", "value": 2}
      ]
    },
    {
      "type": "textfield",
      "fieldName": "email",
      "label": "Email",
      "validators": [
        {"type": "required"},
        {"type": "email"}
      ]
    }
  ],
  "submitAction": {
    "type": "api",
    "method": "POST",
    "url": "/api/contact",
    "body": {"name": "${name}", "email": "${email}"}
  }
}

πŸ’Ύ Local Storage (ObjectBox)

QuicUI uses ObjectBox for blazingly fast local storage:

  • ⚑ Sub-millisecond queries (0.2ms avg)
  • πŸ”’ ACID transactions for data integrity
  • πŸ“¦ 50x faster than SQLite for typical operations
  • πŸ”„ Built for sync scenarios
  • πŸ” Optional encryption support
// Cache UI responses
await QuicUIManager.cache('home', jsonData);

// Retrieve from cache
final cached = await QuicUIManager.getCache('home');

// Offline support with automatic sync
await QuicUIManager.syncOfflineChanges();

πŸ”§ State Management

// Access global state
Consumer<QuicState>(
  builder: (context, state, _) {
    return Text(state.get('userName') ?? 'Guest');
  },
)

// Update state
Provider.of<QuicState>(context, listen: false)
  .set('userName', 'John Doe');

// Listen to events
state.on('userLoggedIn', (data) {
  print('User logged in: $data');
});

🎨 Dynamic Theming

// Define theme as JSON
final theme = {
  "colors": {
    "primary": "#6366F1",
    "secondary": "#EC4899"
  },
  "typography": {
    "heading": {"fontSize": 24, "fontWeight": "bold"}
  }
};

// Apply dynamically at runtime
Provider.of<ThemeManager>(context, listen: false)
  .setTheme(jsonEncode(theme));

πŸ§ͺ Testing

QuicUI includes comprehensive testing utilities:

// Unit tests for JSON parsing
test('Parse simple widget', () {
  final json = '{"type":"text","properties":{"text":"Hello"}}';
  final widget = QuicWidget.fromJson(jsonDecode(json));
  expect(widget.type, equals('text'));
});

// Widget tests
testWidgets('Render QuicText', (tester) async {
  await tester.pumpWidget(
    MaterialApp(home: Scaffold(body: QuicText(text: 'Hello')))
  );
  expect(find.text('Hello'), findsOneWidget);
});

πŸ“Š Performance

Metric Target Status
Widget render < 100ms βœ… Target
DB query < 10ms βœ… Target (ObjectBox)
Cache hit < 1ms βœ… Target
Form validation < 50ms βœ… Target
Network request < 500ms βœ… Target

πŸš€ Development Roadmap

Phase 1-2: Foundation & Widgets (Weeks 1-3)

  • Core models and JSON parser
  • Widget factory and all core widgets
  • Basic rendering engine

Phase 3-4: State & Forms (Weeks 3-5)

  • State management system
  • Action execution engine
  • Complete form system

Phase 5-7: Storage, Theming & Polish (Weeks 5-7)

  • ObjectBox integration
  • Sync mechanism
  • Dynamic theming system
  • Testing & documentation

Target Release: End of Week 7 (v1.0 production-ready)

See ROADMAP.md for detailed timeline.

πŸ”Œ Extensibility

Custom Widgets

class CustomWidgetRegistry {
  static void register(String type, WidgetBuilder builder) {
    // Register custom widget
  }
}

Custom Actions

class CustomActionHandler {
  static void register(String type, ActionHandler handler) {
    // Handle custom actions
  }
}

Custom Validators

class ValidatorRegistry {
  static void register(String type, ValidatorFn validator) {
    // Custom validation logic
  }
}

πŸ”’ Security

  • βœ… JSON schema validation prevents injection
  • βœ… Encrypted local storage (optional)
  • βœ… HTTPS-only API communication
  • βœ… Request signing and verification
  • βœ… Sandbox for custom code execution

πŸ“± Platform Support

Platform Status Min Version
iOS βœ… Full 11.0
Android βœ… Full 5.0 (API 21)
Web βœ… Full Modern browsers
Windows βœ… Full 10+
macOS βœ… Full 10.13+
Linux βœ… Full Ubuntu 18.04+

πŸ“¦ Dependencies

Core Dependencies

  • flutter_bloc: ^9.0.0 - State management (BLoC pattern)
  • equatable: ^2.0.5 - Value equality
  • dio: ^5.7.0 - HTTP client
  • objectbox: ^4.1.1 - Local database
  • json_annotation: ^4.8.1 - JSON serialization

See pubspec.yaml for complete list.

πŸ“– Examples

Complete example applications are available in the /example folder:

  • Basic text and button rendering
  • Form with validation
  • API integration
  • List rendering
  • Theme switching
  • Offline support
  • A/B testing

🀝 Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines.

How to Contribute

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes with tests
  4. Submit a pull request

πŸ› Issue Reporting

Found a bug? Please report it on GitHub with:

  • Minimal reproducible example
  • Flutter/Dart version
  • Platform details
  • Relevant logs

πŸ“ž Support

β˜• Love QuicUI?

If you find QuicUI helpful and want to support its development, consider buying me a coffee! Every cup fuels more features, faster updates, and better documentation.

β˜• Buy Me a Coffee - Help keep QuicUI growing!

Your support helps us:

  • πŸš€ Build new features faster
  • πŸ“š Create better documentation
  • πŸ› Fix bugs quickly
  • πŸ’‘ Implement community requests
  • 🎯 Maintain long-term support

Every contribution is deeply appreciated! ❀️

πŸ“œ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Acknowledgments

Inspired by:

  • Stac - Server-Driven UI inspiration
  • Flutter community and best practices
  • Open-source SDUI pioneers

πŸš€ What's Next?

  1. Review the Implementation Plan
  2. Read the Architecture Guide
  3. Follow the Quick Start
  4. Check the Development Roadmap

Made with ❀️ by the QuicUI team

⭐ If you find QuicUI useful, please give it a star on GitHub!

Libraries

objectbox.g
quicui
QuicUI - Server-Driven UI Framework for Flutter