skyloom_schema 0.10.0-dev.4 copy "skyloom_schema: ^0.10.0-dev.4" to clipboard
skyloom_schema: ^0.10.0-dev.4 copied to clipboard

A headless-first, schema-driven form engine for Flutter.

Skyloom woven-thread S logo

skyloom_schema #

Build validated Flutter forms from typed Dart models or JSON-compatible schemas. Skyloom keeps parsing, state, validation, and rendering separate, so the same form definition can be stored remotely, authored in Dart, or rendered with custom widgets.

What you get #

  • Typed Dart builders with autocomplete
  • JSON parsing and serialization
  • Material 3 rendering for 14 field types
  • Nested objects and repeatable arrays
  • Validation, localization, and structured errors
  • Conditional visibility, enabled, required, and read-only state
  • Async options and async validation
  • Responsive sections and multi-step workflows
  • Provider-neutral file upload state
  • Standard and brutalism themes with true-black dark mode
  • Replaceable field renderers

Install #

flutter pub add skyloom_schema
import 'package:flutter/material.dart';
import 'package:skyloom_schema/skyloom_schema.dart';

Quick start #

Use the typed API when the form is authored inside your Flutter application:

final employeeSchema = SkyloomSchema.form(
  id: 'employee',
  title: 'Employee registration',
  fields: [
    SkyloomField.text(
      key: 'name',
      label: 'Full name',
      validation: SkyloomValidation.rules(
        required: true,
        minLength: 2,
      ),
    ),
    SkyloomField.email(
      key: 'email',
      label: 'Email address',
      validation: SkyloomValidation.rules(
        required: true,
        email: true,
      ),
    ),
    SkyloomField.select(
      key: 'role',
      label: 'Role',
      options: const [
        FieldOption(label: 'Developer', value: 'developer'),
        FieldOption(label: 'Designer', value: 'designer'),
      ],
    ),
  ],
);

Render it with SkyloomForm:

SkyloomForm(
  schema: employeeSchema,
  initialValues: const {'role': 'developer'},
  onChanged: (values) => debugPrint('$values'),
  onSubmit: (values) async {
    await saveEmployee(values);
  },
)

Skyloom validates before submission and returns JSON-compatible nested values.

JSON schemas #

Use SkyloomForm.fromJson for schemas loaded from an API, asset, database, or configuration file:

const schema = <String, Object?>{
  'schemaVersion': '1.0',
  'id': 'contact',
  'title': 'Contact details',
  'fields': [
    {
      'key': 'name',
      'type': 'text',
      'label': 'Name',
      'validation': {'required': true},
    },
    {
      'key': 'email',
      'type': 'email',
      'label': 'Email',
      'validation': {'required': true, 'email': true},
    },
  ],
};

SkyloomForm.fromJson(
  schema: schema,
  onSubmit: (values) => debugPrint('$values'),
)

In Dart maps you may use FormType.text, FormType.email, and the other constants for autocomplete. Real JSON uses strings such as "text".

To parse without rendering:

final form = const SchemaParser().parse(schema);
final json = form.toJson();

Invalid definitions throw SchemaParseException with a schema path. Use SchemaParser.validate when an editor needs multiple diagnostics in one pass. The parser also supports configurable complexity limits.

The complete contract is documented in Schema 1.0.

Built-in fields #

Type Purpose
text Single-line text
email Email input and validation
password Obscured text
number Numeric input
textarea Multi-line text
checkbox Boolean confirmation
switch Boolean setting
radio Single choice, row or column
select Local or remotely loaded choice
chip Single or multiple chip choices
date Calendar date selection
file Single or multiple uploaded-file references
object Nested fields
array Repeatable primitive, object, or nested items

Unknown type names can be preserved for application-provided renderers.

Validation and errors #

Built-in validation covers required values, length, numeric ranges, date ranges, email, URL, pattern/regex, array counts, file constraints, and cross-field comparisons.

Choose when validation runs:

SkyloomForm.fromJson(
  schema: schema,
  validationMode: SkyloomValidationMode.onBlur,
  onSubmit: submit,
)

Available modes are onChange, onBlur, onSubmit, and manual.

Register application validation by name:

SkyloomForm.fromJson(
  schema: schema,
  validators: {
    'reservedName': (value, values) =>
        value == 'admin' ? 'This name is reserved.' : null,
  },
)

Use SkyloomFormController.applyErrors for backend errors. Errors retain stable SkyloomValidationCode values, while SkyloomMessages controls visible validation and interface text.

final controller = SkyloomFormController(schema: parsedSchema);

controller.applyErrors(
  fieldErrors: {
    'email': ['This address is already registered.'],
  },
);

controller.focusField('email');

Dynamic forms #

Conditions can change whether a field is visible, enabled, required, or read-only. Dependencies can clear values and reload options when another field changes.

{
  'key': 'state',
  'type': 'select',
  'label': 'State',
  'dependsOn': ['country'],
  'dataSource': {'handler': 'states'},
  'dependencyConfig': {
    'clearOnChange': true,
    'reloadDataOnChange': true,
  },
}

Register the application-owned callback in Dart:

SkyloomForm.fromJson(
  schema: schema,
  dataSources: {
    'states': (request) async {
      return api.states(request.dependencyValues['country']);
    },
  },
)

Named async validators support debouncing and optional result caching:

asyncValidators: {
  'emailAvailable': (value, context) async {
    return await api.emailExists('$value')
        ? 'This email is already registered.'
        : null;
  },
},

Nested data, sections, and workflows #

Object and array fields create values such as:

{
  "address": {"city": "Chennai"},
  "contacts": [
    {"name": "Asha", "phone": "+91 90000 00000"}
  ]
}

uiSchema provides ordering and twelve-column mobile, tablet, and desktop spans. Sections group or collapse fields. Steps add Back, Next, per-step validation, conditional pages, progress, and final submission.

Large forms can use SkyloomFormLayout.lazy; nested paths, focus requests, error summaries, and hidden/collapsed invalid fields remain controller-aware.

See the runnable example application for complete nested, responsive, and workflow definitions.

File uploads #

Skyloom does not choose a storage provider or file picker. A file field calls a registered handler; your application picks/uploads files and returns portable SkyloomUploadedFile references.

SkyloomForm.fromJson(
  schema: schema,
  fileUploadHandlers: {
    'resumeUpload': (request) async {
      final uploaded = await uploadResume();
      return [
        SkyloomUploadedFile(
          id: uploaded.id,
          name: uploaded.name,
          url: uploaded.url,
          mimeType: uploaded.mimeType,
          size: uploaded.size,
        ),
      ];
    },
  },
)

Themes #

Skyloom follows the host application's ThemeData by default. The optional SkyloomTheme helper provides coordinated application and form styling.

const appearance = SkyloomTheme(
  seedColor: Colors.teal,
  visualStyle: SkyloomVisualStyle.standard,
  pureBlackDark: true,
);

MaterialApp(
  theme: appearance.lightTheme,
  darkTheme: appearance.darkTheme,
  themeMode: ThemeMode.system,
  home: const MyPage(),
)

Two built-in styles are available:

  • SkyloomVisualStyle.standard: rounded Material 3 surfaces
  • SkyloomVisualStyle.brutalism: square corners, heavy outlines, strong type, and harder elevation

Provide lightColorScheme and darkColorScheme for complete brand control. SkyloomThemeController can switch brightness, style, and seed color at runtime:

controller.toggleBrightness(Theme.of(context).brightness);
controller.toggleVisualStyle();
controller.setSeedColor(Colors.orange);
controller.setThemeMode(ThemeMode.system);

The example's Themes screen compares both styles using the same live form.

Material, Cupertino, and custom UI #

The schema parser, controllers, validation engine, and renderer contract are UI-independent. The ready-to-use SkyloomForm shell and its built-in renderers use Material 3.

Custom SkyloomFieldRenderer implementations may return any Flutter widget, including Cupertino or widgets from another UI library:

import 'package:flutter/cupertino.dart';

final class CupertinoSwitchRenderer implements SkyloomFieldRenderer {
  const CupertinoSwitchRenderer();

  @override
  Widget build(BuildContext context, SkyloomRendererContext field) {
    return Row(
      children: [
        Expanded(child: Text(field.fieldSchema.label ?? field.fieldPath)),
        CupertinoSwitch(
          value: field.value == true,
          onChanged: field.fieldController.enabled
              ? (value) => field.setValue(value)
              : null,
        ),
      ],
    );
  }
}

SkyloomForm(
  schema: employeeSchema,
  renderers: const {
    FormType.switchField: CupertinoSwitchRenderer(),
  },
)

This supports mixed or field-level Cupertino rendering today. A complete Cupertino form shell—including Cupertino sections, actions, progress, dialogs, and error presentation—is not bundled yet.

Controller API #

Use SkyloomFormController when code outside the widget must manage the form:

final controller = SkyloomFormController(schema: employeeSchema);

controller.setValue('name', 'Asha');
controller.value('name');
controller.values;
controller.validate();
controller.reset();

SkyloomForm(
  schema: employeeSchema,
  controller: controller,
  onSubmit: saveEmployee,
)

The controller also manages arrays, async state, step navigation, server errors, focus/reveal requests, and JSON-safe submitted values.

Run the example #

The example is an interactive component and schema explorer with live previews for all built-in fields and both visual styles.

flutter run -t example/main.dart -d chrome

Use any available Flutter device instead of chrome when preferred.

More documentation #

Development checks #

dart analyze
flutter test
flutter pub publish --dry-run

License #

MIT. See LICENSE.

1
likes
160
points
469
downloads
screenshot

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A headless-first, schema-driven form engine for Flutter.

Repository (GitHub)
View/report issues

Topics

#form #schema #validation #material-design

License

MIT (license)

Dependencies

flutter

More

Packages that depend on skyloom_schema