sdui_kit 0.0.1 copy "sdui_kit: ^0.0.1" to clipboard
sdui_kit: ^0.0.1 copied to clipboard

Platformweb

A Server-Driven UI (SDUI) Flutter plugin that renders dynamic widgets from JSON. Supports text, title, description, table, grid, array, section, action, docs, html, and details components — each with [...]

sdui_kit #

Server-Driven UI for Flutter — render dynamic widget layouts from JSON without shipping a new app update.

┌─────────────────────────────────────────────────────────────┐
│   Server sends JSON  →  sduiParser()  →  SduiView renders  │
└─────────────────────────────────────────────────────────────┘

Table of Contents #

  1. Installation
  2. Quick Start
  3. How It Works
  4. Components Reference
  5. Full JSON Payload Example
  6. API Reference
  7. Theming
  8. Custom PDF Viewer
  9. Extending with Custom Types

Installation #

Add to your pubspec.yaml:

dependencies:
  sdui_kit: ^0.0.1

Then:

flutter pub get

Quick Start #

import 'package:sdui_kit/sdui_kit.dart';

// 1. Parse the server JSON
final items = sduiParser(json['viewData']);

// 2. Render
SduiView(
  items: items,
  primaryColor: Colors.indigo,
  onAction: (action) {
    Navigator.pushNamed(context, action.route);
  },
)

That's it. The server controls what components appear, in what order, and with which style.


How It Works #

Server JSON
    │
    ▼
sduiParser(raw)                   parses List → List<SduiItem>
    │
    ▼
SduiView(items: items)            wraps in SduiScope (theme propagation)
    │
    ▼
SduiItemView(item: item)          routes each item by type + style
    │
    ├─ type: "text"   → SduiDefaultText / SduiTextStyle1 / ...
    ├─ type: "grid"   → SduiDefaultGrid / SduiGridStyle1 / ...
    ├─ type: "section" → SduiDefaultSection (recurses SduiView)
    └─ ...

Each SduiItem has:

Field Type Description
type String Component type: text, grid, table, etc.
label String Label / heading shown in the component
style String Visual variant: default, style1, style2
column int Grid column count (default: 2)
color String Color key for colorized components
data dynamic Component-specific payload (String / List / Map)

Components Reference #


1. text #

Displays a key–value pair. Four visual styles.

Styles

Style Visual Description
default Label left · Value right, with optional copy button
style1 Card with gradient icon, label above, large value below
style2 Pill label badge on left · Bold value on right
style3 Colored badge box (uses color field)

JSON Schema

{
  "type": "text",
  "label": "Employee Name",
  "data": "John Smith",
  "style": "default"
}
{
  "type": "text",
  "label": "Status",
  "data": "Active",
  "style": "style3",
  "color": "green"
}

Available color values: primary (default), red, green, orange, blue

Visual (default)

┌─────────────────────────────────────────┐
│  Employee Name           John Smith     │
└─────────────────────────────────────────┘

Visual (style1)

┌─────────────────────────────────────────┐
│  [📊]  Employee Name                    │
│        John Smith                       │
└─────────────────────────────────────────┘

Visual (style2)

┌─────────────────────────────────────────┐
│  [LABEL]              John Smith        │
└─────────────────────────────────────────┘

Visual (style3)

┌─────────────────────────────────────────┐
│  Active  ← green colored badge box      │
└─────────────────────────────────────────┘

2. title #

Section heading. Two styles.

Styles

Style Visual Description
default Bold primary-colored text
style1 Left black accent bar + bold text

JSON Schema

{"type": "title", "data": "Dashboard Overview", "style": "default"}
{"type": "title", "data": "Performance Metrics", "style": "style1"}

Visual (default)

  Dashboard Overview
  ─────────────────

Visual (style1)

  ▌ Performance Metrics

3. description #

Long-form text. Two styles.

Styles

Style Visual Description
default Optional label above, wrapped text below
style1 White card with left accent bar + "Description" header

JSON Schema

{
  "type": "description",
  "data": "This is a long explanation...",
  "style": "default"
}
{
  "type": "description",
  "data": "This is a description with style1.",
  "style": "style1"
}

Visual (default)

  ┌─────────────────────────────────────────┐
  │  This is a long explanation of the      │
  │  feature you are reading about...       │
  └─────────────────────────────────────────┘

Visual (style1)

  ┌──────────────────────────────────────────┐
  │  ▌ Description                           │
  │                                          │
  │  This is a description with style1.      │
  └──────────────────────────────────────────┘

4. details #

Title + description pair. One style.

JSON Schema

{
  "type": "details",
  "label": "Project Info",
  "style": "default",
  "data": {
    "title": "Q4 Goals",
    "description": "Complete the migration and launch the SDK.",
    "style": "default"
  }
}

Visual

  Q4 Goals
  ────────
  Complete the migration and launch the SDK.

5. section #

Container that groups nested components. Supports recursion.

Styles

Style Visual Description
default White card with label header, children inside
style1 Collapsible ExpansionTile card

JSON Schema

{
  "type": "section",
  "label": "Employee Details",
  "style": "default",
  "data": [
    {"type": "text", "label": "ID", "data": "EMP-00142", "style": "default"},
    {"type": "text", "label": "Role", "data": "Developer", "style": "style1"}
  ]
}
{
  "type": "section",
  "label": "Collapsible Section",
  "style": "style1",
  "data": [
    {"type": "title", "data": "Phase 1", "style": "style1"}
  ]
}

Visual (default)

  ┌──────────────────────────────────────────┐
  │  Employee Details                        │
  │  ──────────────────────────────────────  │
  │    ID                     EMP-00142      │
  │    [📊] Role                             │
  │         Developer                        │
  └──────────────────────────────────────────┘

Visual (style1 — expandable)

  ┌──────────────────────────────────────────┐
  │  Collapsible Section              ▼      │
  │  ──────────────────────────────────────  │
  │    ▌ Phase 1                             │
  └──────────────────────────────────────────┘

6. table #

Data table with dynamic columns. Three styles.

Styles

Style Visual Description
default Simple DataTable with border, horizontal scroll
style1 Card-shadowed table, primary-tinted header row
style2 Full-width table, solid primary header, alternating row colors

JSON Schema

{
  "type": "table",
  "label": "Sales Report",
  "style": "default",
  "data": [
    {"Product": "Widget A", "Qty": "120", "Revenue": "$2,400"},
    {"Product": "Widget B", "Qty": "85",  "Revenue": "$1,700"}
  ]
}

data is List<Map<String, String>>. All values must be strings.

Visual (default)

  Table (Default)
  ┌─────────────┬──────┬──────────┐
  │ Product     │ Qty  │ Revenue  │
  ├─────────────┼──────┼──────────┤
  │ Widget A    │ 120  │ $2,400   │
  │ Widget B    │ 85   │ $1,700   │
  └─────────────┴──────┴──────────┘

Visual (style1)

  Sales Report
  ┌──────────────────────────────────────┐
  │ ░ Product   │ ░ Qty  │ ░ Revenue     │  ← primary tint header
  ├─────────────┼────────┼───────────────┤
  │   Widget A  │  120   │   $2,400      │
  └─────────────┴────────┴───────────────┘

Visual (style2)

  ████████████ Product ████████████  ← solid primary header (white text)
  │ Widget A    │ 120  │ $2,400     │  ← row
  │ Widget B    │ 85   │ $1,700     │  ← alternating

7. grid #

Grid cards showing metrics. Items have type: "main" or type: "sub". Three styles.

Styles

Style Visual Description
default Simple white cards in a grid, value large
style1 Main = gradient card with icon + trend; Sub = white card + badge
style2 Same layout as style1 but sub-cards use color for theming

JSON Schema

{
  "type": "grid",
  "style": "style1",
  "column": 2,
  "data": [
    {
      "label": "Total Sales",
      "type": "main",
      "value": "5,280",
      "status": "up",
      "colorOne": "0xFF1565C0",
      "colorTwo": "0xFF0D47A1"
    },
    {
      "label": "Returns",
      "type": "sub",
      "value": "34",
      "badge": "Today"
    }
  ]
}
Field Applies to Description
type all "main" or "sub"
label all Card label text
value all Large value displayed
status main/sub "up" → trending up icon, "down" → trending down
colorOne main Gradient start (hex: "0xFF1565C0")
colorTwo main Gradient end (hex: "0xFF0D47A1")
badge sub Small badge label (e.g. "Today")
color sub Color key for style2: red,green,etc.

Visual (style1)

  ┌──────────────────┐  ┌──────────────────┐
  │ [📊]             │  │ [📊]             │
  │                  │  │                  │
  │ Total Sales      │  │ Profit           │  ← gradient cards (main)
  │ 5,280    ↑       │  │ $41K     ↑       │
  └──────────────────┘  └──────────────────┘
  ┌──────────────────┐  ┌──────────────────┐
  │ [🕐]  [Today]    │  │ [🕐]  [Q4]       │
  │ Returns          │  │ Expenses         │  ← white cards (sub)
  │ 34               │  │ $12K             │
  └──────────────────┘  └──────────────────┘

8. array #

List of string items. Three display styles.

Styles

Style Visual Description
default Chip tags in a Wrap layout
style1 Bordered container with label icon each
style2 Bullet point list

JSON Schema

{
  "type": "array",
  "label": "Tech Stack",
  "style": "default",
  "data": ["Flutter", "Dart", "Firebase", "Node.js"]
}

Numbers in data are automatically cast to String.

Visual (default)

  Tech Stack
  [Flutter] [Dart] [Firebase] [Node.js]

Visual (style1)

  Features
  ┌──────────────────────┐  ┌──────────────────────┐
  │ 🏷 Real-time sync    │  │ 🏷 Offline support   │
  └──────────────────────┘  └──────────────────────┘

Visual (style2)

  Requirements
  • Flutter SDK 3.10+
  • Dart 3.0+
  • Internet connection

9. docs #

File/document viewer (PDF, images). Two styles.

Styles

Style Visual Description
default 2-column grid of tappable document cards with gradient
style2 Large preview area + horizontal tab list below

JSON Schema

{
  "type": "docs",
  "label": "Attachments",
  "style": "default",
  "data": [
    {
      "key": "contract",
      "title": "Contract Document",
      "url": "https://example.com/doc.pdf",
      "mime": "application/pdf"
    },
    {
      "key": "photo",
      "title": "Profile Photo",
      "url": "https://example.com/photo.jpg",
      "mime": "image/jpeg"
    }
  ]
}
Field Description
key Unique identifier for the document
title Display name (falls back to key)
url Remote URL
mime MIME type: application/pdf, image/png, etc

Tapping any document opens a modal dialog. For PDF, provide a pdfViewerBuilder — see Custom PDF Viewer.

Visual (default)

  ┌──────────────────────┐  ┌──────────────────────┐
  │ [📄] Contract Doc  › │  │ [🖼] Profile Photo  › │
  └──────────────────────┘  └──────────────────────┘

Visual (style2)

  ┌──────────────────────────────────────────────────┐
  │                                                  │
  │            [Large preview area]                  │
  │                                                  │
  └──────────────────────────────────────────────────┘
  ┌──────────────────────┐  ┌──────────────────────┐
  │ [📄] Contract Doc    │  │ [🖼] Profile Photo    │  ← tabs
  └──────────────────────┘  └──────────────────────┘

10. action #

Button that fires the onAction callback. Three styles.

Styles

Style Visual Description
default Full-width gradient button, square corners
action1 Full-width gradient button, rounded (pill) corners
action2 Full-width outlined gradient-text button

JSON Schema

{
  "type": "action",
  "label": "Submit Application",
  "style": "default",
  "data": {
    "route": "/apply",
    "id": "form-001",
    "code": "APPLY",
    "type": "primary",
    "baseApi": "/api/v1"
  }
}

data.route, data.id, data.code, data.type, data.baseApi are all passed to onAction.

Visual (default)

  ┌──────────────────────────────────────────────────┐
  │          ▓▓▓ Submit Application ▓▓▓              │  ← gradient fill
  └──────────────────────────────────────────────────┘

Visual (action1)

  (          ▓▓▓ View Details ▓▓▓                  )  ← rounded pill

Visual (action2)

  (  - - - - - Cancel Request - - - - - - - - -  )   ← outlined + gradient text

11. html #

Renders an HTML string using flutter_widget_from_html.

JSON Schema

{
  "type": "html",
  "label": "Terms & Conditions",
  "style": "default",
  "data": "<h2>Terms</h2><p>By using this app...</p><ul><li>Item 1</li></ul>"
}

HTML tags supported: h1h6, p, ul, ol, li, strong, em, a, img, table, and more.

Visual

  Terms & Conditions

  Terms
  ═════
  By using this app...
  • Item 1

Full JSON Payload Example #

This is the complete test payload demonstrating every component type:

{
  "status": true,
  "data": {
    "id": "0111",
    "name": "View data documentation",
    "viewData": [
      { "type": "text",        "label": "Text (Default)", "data": "This is a default text item.", "style": "default" },
      { "type": "text",        "label": "Text (Style 1)", "data": "This is text with style1.",    "style": "style1"  },
      { "type": "text",        "label": "Text (Style 2)", "data": "This is text with style2.",    "style": "style2"  },
      { "type": "text",        "label": "Text (Style 3)", "data": "This is text with style3.",    "style": "style3"  },
      { "type": "title",       "data": "Title (Default)", "style": "default" },
      { "type": "title",       "data": "Title (Style 1)", "style": "style1"  },
      { "type": "description", "data": "This is a default description.",      "style": "default" },
      { "type": "description", "data": "This is a description with style1.",  "style": "style1"  },
      {
        "type": "details",
        "label": "Details Section",
        "style": "default",
        "data": { "title": "Detail Title", "description": "Detail Description content goes here." }
      },
      {
        "type": "section",
        "label": "Section (Default)",
        "style": "default",
        "data": [{ "type": "text", "label": "Inside Section", "data": "Nested text item", "style": "default" }]
      },
      {
        "type": "section",
        "label": "Section (Style 1 — Collapsible)",
        "style": "style1",
        "data": [{ "type": "title", "data": "Section Title", "style": "default" }]
      },
      {
        "type": "table",
        "label": "Table (Default)",
        "style": "default",
        "data": [{ "Col1": "Val1", "Col2": "Val2" }, { "Col1": "Val3", "Col2": "Val4" }]
      },
      { "type": "table", "label": "Table (Style 1)", "style": "style1", "data": [{ "Header1": "Data1", "Header2": "Data2" }] },
      { "type": "table", "label": "Table (Style 2)", "style": "style2", "data": [{ "Key": "Value", "Status": "Active" }]  },
      {
        "type": "grid",
        "style": "default",
        "column": 2,
        "data": [
          { "label": "Main Item", "type": "main", "value": "100", "colorOne": "0xFFE0E0E0", "colorTwo": "0xFFFFFFFF" },
          { "label": "Sub Item",  "type": "sub",  "value": "50",  "badge": "New" }
        ]
      },
      {
        "type": "grid",
        "style": "style1",
        "column": 2,
        "data": [
          { "label": "Total Sales", "type": "main", "value": "5,280", "status": "up", "colorOne": "0xFF1565C0", "colorTwo": "0xFF0D47A1" },
          { "label": "Returns",     "type": "sub",  "value": "34",    "badge": "Today" }
        ]
      },
      {
        "type": "grid",
        "style": "style2",
        "column": 2,
        "data": [
          { "label": "Conversions", "type": "main", "value": "68%" },
          { "label": "Bounce Rate", "type": "sub",  "value": "24%", "badge": "Low", "color": "green" }
        ]
      },
      {
        "type": "docs",
        "style": "default",
        "data": [
          { "key": "doc1", "title": "Document 1", "url": "https://...", "mime": "application/pdf" },
          { "key": "img1", "title": "Image 1",    "url": "https://...", "mime": "image/png"       }
        ]
      },
      {
        "type": "docs",
        "style": "style2",
        "data": [{ "key": "doc2", "title": "Document 2", "url": "https://...", "mime": "application/pdf" }]
      },
      { "type": "action", "label": "Action Button (Default)", "style": "default", "data": { "route": "/some/route", "id": "123", "code": "ACT001", "type": "primary", "baseApi": "/api/v1" } },
      { "type": "action", "label": "Action Button (Style 1)", "style": "action1", "data": { "route": "/style1/route", "id": "456" } },
      { "type": "action", "label": "Action Button (Style 2)", "style": "action2", "data": { "route": "/style2/route", "id": "789" } },
      { "type": "array", "label": "Array (Default)", "style": "default", "data": ["Item 1", "Item 2", "Item 3"] },
      { "type": "array", "label": "Array (Style 1)", "style": "style1",  "data": ["Item A", "Item B"] },
      { "type": "array", "label": "Array (Style 2)", "style": "style2",  "data": ["First item", "Second item"] },
      { "type": "html",  "label": "Html data", "style": "default", "data": "<h1>Hello</h1><p>World</p>" }
    ]
  },
  "title": "Test View Data",
  "message": "Data fetched successfully.",
  "error": ""
}

API Reference #

sduiParser(dynamic source) → List<SduiItem> #

Converts a raw JSON list into typed SduiItem objects.

final items = sduiParser(json['viewData']);

SduiView #

The main rendering widget.

SduiView({
  required List<SduiItem> items,
  Color? primaryColor,                   // brand color (defaults to Theme.primaryColor)
  SduiActionCallback? onAction,          // called when action button tapped
  SduiPdfViewerBuilder? pdfViewerBuilder, // optional PDF widget builder
})

SduiItem #

class SduiItem {
  final String  type;    // "text" | "title" | "description" | "details" |
                         // "section" | "table" | "grid" | "array" |
                         // "docs" | "action" | "html"
  final String  label;
  final String  style;   // "default" | "style1" | "style2" | "action1" | "action2"
  final int     column;  // grid column count (default: 2)
  final String? color;   // color key for colorized components
  final dynamic data;    // component-specific payload
}

ActionViewData #

Payload delivered to onAction:

class ActionViewData {
  final String  route;
  final String? id;
  final String? code;
  final String? type;
  final String? baseApi;
}

Usage:

SduiView(
  items: items,
  onAction: (ActionViewData action) {
    switch (action.route) {
      case '/apply':
        Navigator.pushNamed(context, '/apply', arguments: action.id);
        break;
      case '/cancel':
        showCancelDialog(context, id: action.id);
        break;
    }
  },
)

Theming #

primaryColor drives all component theming. Pass it once to SduiView:

SduiView(
  items: items,
  primaryColor: const Color(0xFF1565C0),  // deep blue
)

For nested section components, the theme propagates automatically via SduiScope.

To use the theme outside SduiView:

final primary = SduiScope.of(context).primaryColor;

Custom PDF Viewer #

By default, PDF files show a placeholder. To enable actual PDF rendering, install your preferred viewer (e.g. syncfusion_flutter_pdfviewer) and pass it via pdfViewerBuilder:

# pubspec.yaml
dependencies:
  syncfusion_flutter_pdfviewer: ^latest
SduiView(
  items: items,
  pdfViewerBuilder: (String url) {
    return SfPdfViewer.network(url);
  },
)

Extending with Custom Types #

To handle component types not built into the plugin (e.g. ytVideo), use SduiItemView directly and wrap it:

class MyAppItemView extends StatelessWidget {
  final SduiItem item;
  const MyAppItemView({required this.item});

  @override
  Widget build(BuildContext context) {
    if (item.type == 'ytVideo') {
      return YoutubePlayer(url: item.data as String);
    }
    // Fall back to plugin renderer for everything else
    return SduiItemView(item: item);
  }
}

Then use _SduiViewBody-like logic to build your custom SduiView override.


Component Quick Reference #

Type Styles data payload type
text default, style1, style2, style3 String
title default, style1 String
description default, style1 String
details default { title, description }
section default, style1 List<SduiItem json>
table default, style1, style2 List<Map<String, String>>
grid default, style1, style2 List<GridViewData json>
array default, style1, style2 List<String>
docs default, style2 List<{ key, title, url, mime }>
action default, action1, action2 { route, id, code, type, baseApi }
html default String (raw HTML)

License #

MIT

0
likes
120
points
0
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Server-Driven UI (SDUI) Flutter plugin that renders dynamic widgets from JSON. Supports text, title, description, table, grid, array, section, action, docs, html, and details components — each with multiple styles.

Repository (GitHub)

Topics

#widget #json #dynamic-ui

License

MIT (license)

Dependencies

flutter, flutter_widget_from_html

More

Packages that depend on sdui_kit