Skip to content

Ryanditko/flutter-server-driven-ui

Repository files navigation

Server-Driven UI in Flutter

image

Build dynamic screens from JSON contracts — zero hardcoded layouts.

Flutter Dart Material 3 JSON License CI codecov

Architecture Docs · Mock Server


Overview

A production-style server-driven UI architecture built entirely with Flutter and Dart. Every layout, component, and navigation action is defined by JSON contracts that the engine renders dynamically at runtime.

In a server-driven UI (also called Backend-Driven Content), the client is a generic rendering engine. Instead of writing widgets for each screen, you define screens as data — a JSON tree describing which components to render, how to lay them out, and what actions they trigger.


Data Flow

flowchart LR
  subgraph source ["Data Source"]
    JSON["JSON Contract"]
    Remote["HTTP Server"]
  end
  subgraph engine ["Rendering Engine"]
    Client["ApiClient"]
    Cache["CachedApiClient"]
    Model["ScreenContract"]
    Expr["ExpressionContext"]
    Theme["ThemeContract"]
    Parser["ComponentParser"]
    Validator["ContractValidator"]
  end
  subgraph output ["Output"]
    Tree["Widget Tree"]
    UI["Rendered UI"]
  end
  JSON -->|"load"| Client
  Remote -->|"fetch"| Client
  Client --> Cache
  Cache --> Model
  Model --> Validator
  Model --> Expr
  Model --> Theme
  Expr --> Parser
  Model --> Parser
  Parser --> Tree
  Tree --> UI
Loading

Architecture

graph TB
  subgraph core ["lib/core"]
    models["models/"]
    network["network/"]
    parser["parser/"]
    expression["expression/"]
    theme["theme/"]
    validator["validator/"]
    animation["animation/"]
    error["error/"]
    utils["utils/"]
  end
  subgraph presentation ["lib/presentation"]
    pages["pages"]
    widgets["widgets/ ×106"]
  end
  subgraph playground ["lib/playground"]
    pg_page["PlaygroundPage"]
    pg_widgets["editor + preview + selector"]
  end
  network --> models
  models --> parser
  expression --> parser
  animation --> parser
  error --> parser
  parser --> widgets
  widgets --> pages
  pg_widgets --> parser
Loading

Features

Components (106 types)

Category Components
Core Layout column · row · container · card · listView · stack · positioned · wrap · spacer · responsive · expanded · flexible
Layout Wrappers center · align · padding · sizedBox · constrainedBox · fittedBox · fractionallySizedBox · intrinsicHeight · intrinsicWidth · limitedBox · overflowBox · aspectRatio · baseline · opacity · clipRRect · clipOval · safeArea · rotatedBox · ignorePointer · absorbPointer · offstage · visibility
Decorators material · hero · decoratedBox · indexedStack · transform · backdropFilter · banner
Scrollables scrollView · gridView · pageView · customScrollView · sliverList · sliverGrid
Interactives inkWell · gestureDetector · tooltip · dismissible · draggable · longPressDraggable
Animated animatedContainer · animatedOpacity · animatedCrossFade · animatedSwitcher · animatedAlign · animatedPadding · animatedPositioned · animatedSize · animatedScale
Tiles listTile · expansionTile · switchListTile · checkboxListTile · radioListTile
Tables table · tableRow · tableCell · dataTable
Text Variants selectableText · richText · defaultTextStyle
Button Variants textButton · outlinedButton · iconButton · floatingActionButton · segmentedButton
Media & Display placeholder · circleAvatar · verticalDivider · popupMenuButton · searchBar · searchAnchor · tooltip
Leaf text · button · image · input · divider · icon · chip · progress · badge
Interactive Inputs switch · checkbox · dropdown · tabBar · carousel · slider · rangeSlider · radio

Actions (7 types)

navigate · snackbar · submit · goBack · openUrl · copyToClipboard · showDialog

Engine Capabilities

  • Expression Engine{{variable}} template interpolation and conditional visibility
  • Dynamic Theming — per-screen color, typography, and brightness from JSON
  • Contract Validation — schema checks before rendering with detailed warnings
  • Remote API + CachingHttpApiClient for HTTP fetching, CachedApiClient with TTL
  • Playground — live JSON editor with syntax highlighting, split-view preview, and screen selector
  • Form Validation — declarative required, minLength, maxLength, pattern rules from JSON
  • Entrance AnimationsfadeIn, slideUp, slideLeft, scale per-component via props.animation
  • Error Boundary — graceful error handling per component, prevents cascading failures
  • AccessibilitySemantics labels on interactive components (buttons, chips, inputs, switches, checkboxes), text variants, media (images, icons, avatars, badges, progress indicators, dividers), and interactive wrappers (inkWell, gestureDetector)
  • Responsive Layout — breakpoint system (compact / medium / expanded) with responsive, expanded, flexible
  • Page Transitions — animated navigation with fade, slide-up, and horizontal slide routes
  • Mock Backend — standalone Dart Shelf server serving contracts via REST API

Demo Screens

Screen Description
home Welcome page with navigation to all demos and a banner image
profile User profile with avatar, details card, and snackbar action
form Feedback form with validation, entrance animations, and submit
components_showcase Every core component type in one screen
expressions_demo Template interpolation and conditional visibility
theme_demo Dark theme applied via JSON contract
new_components Dropdown, tab bar, and carousel showcase
advanced_components Layout wrappers, decorators, tiles, buttons, text variants, and misc widgets

Quick Start

flutter pub get
flutter run

The landing page offers two modes:

  • App Demo — navigate through pre-built screens loaded from assets/screens/
  • Playground — edit JSON contracts and preview rendered output in real-time

Running the Mock Server

cd server
dart pub get
dart run bin/server.dart

The server starts on http://localhost:8080 and serves contracts from assets/screens/.


JSON Contract Example

{
  "schemaVersion": "1.0",
  "context": {
    "user": { "name": "Ryanditko" }
  },
  "theme": {
    "primaryColor": "#820AD1",
    "brightness": "dark"
  },
  "screen": {
    "id": "example",
    "title": "Hello",
    "root": {
      "type": "column",
      "props": { "crossAxisAlignment": "stretch", "padding": 24 },
      "children": [
        {
          "type": "text",
          "props": {
            "content": "Hi, {{user.name}}!",
            "style": { "fontSize": 24 },
            "animation": { "type": "fadeIn", "duration": 500 }
          }
        },
        {
          "type": "input",
          "id": "email",
          "props": {
            "label": "Email",
            "validation": {
              "required": true,
              "pattern": "^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$",
              "message": "Enter a valid email"
            }
          }
        },
        {
          "type": "button",
          "props": { "label": "Go to Profile" },
          "action": { "type": "navigate", "targetScreenId": "profile" }
        }
      ]
    }
  }
}

Adding a New Screen

  1. Create a JSON file at assets/screens/your_screen.json
  2. Reference it from any button action:
{ "type": "navigate", "targetScreenId": "your_screen" }

No Dart code changes needed.

Adding a New Component

  1. Create a builder function in lib/presentation/widgets/
  2. Register it in ComponentParser._registerDefaults():
_registry.register('yourType', buildYourComponent);

Documentation


Tech Stack

Concern Technology
Language Dart
Framework Flutter
Design System Material 3
Data Format JSON
Backend Shelf
CI/CD GitHub Actions
Architecture Server-Driven UI / Backend-Driven Content

Built with Flutter + Material Design 3

About

Server-driven UI architecture built with Flutter and Dart. Screens, layouts, and navigation are fully described as JSON contracts — the Flutter app dynamically builds the widget tree at runtime based on these definitions. Supports local assets and remote REST APIs as data sources.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages