Property Types
The Property System provides built-in property types for all common value categories. Each type is a final class extending Property<T> with appropriate defaults and editor support.
Type Overview
| Property | Type T | Default | Builder Method |
|---|---|---|---|
StringProperty | String | '' | string() |
IntProperty | int | 0 | integer() |
DoubleProperty | double | 0.0 | decimal() |
BoolProperty | bool | false | boolean() |
DateTimeProperty | DateTime | DateTime.now() | dateTime() |
OptionalStringProperty | String? | null | optionalText() |
OptionalIntProperty | int? | null | optionalInteger() |
OptionalDoubleProperty | double? | null | optionalDecimal() |
OptionalBoolProperty | bool? | null | optionalBoolean() |
OptionalDateTimeProperty | DateTime? | null | optionalDateTime() |
EnumProperty<T> | T | First option | enumeration<T>() |
ListProperty<T> | List<T> | [] | list<T>() |
UnionProperty | String | Selected key | (direct constructor) |
ReadOnlyProperty<T> | T | Required | readonly<T>() |
StringProperty
The most common property type. Renders as a text field.
final title = StringProperty(
key: 'title',
label: 'Course Title',
defaultValue: '',
required: true,
validators: [
PropertyValidators.minLength(3),
PropertyValidators.maxLength(200),
],
help: 'The display name for this course',
);Using the builder:
b.string('title', 'Course Title',
required: true,
validators: [PropertyValidators.minLength(3)],
);IntProperty
For integer values. Renders as a number input.
final duration = IntProperty(
key: 'duration',
label: 'Duration (hours)',
defaultValue: 1,
validators: [
PropertyValidators.min(1),
PropertyValidators.max(200),
],
);Using the builder:
b.integer('duration', 'Duration (hours)',
defaultValue: 1,
validators: [PropertyValidators.min(1)],
);DoubleProperty
For floating-point values. Renders as a decimal number input.
final price = DoubleProperty(
key: 'price',
label: 'Course Price',
defaultValue: 0.0,
validators: [PropertyValidators.min(0)],
);Using the builder:
b.decimal('price', 'Course Price',
defaultValue: 0.0,
validators: [PropertyValidators.min(0)],
);BoolProperty
For boolean values. Renders as a toggle switch.
final featured = BoolProperty(
key: 'featured',
label: 'Feature on Homepage',
defaultValue: false,
);Using the builder:
b.boolean('featured', 'Feature on Homepage', defaultValue: false);DateTimeProperty
For date and time values. Renders as a date/time picker. Defaults to DateTime.now() if no default is provided.
final startDate = DateTimeProperty(
key: 'startDate',
label: 'Start Date',
required: true,
);Using the builder:
b.dateTime('startDate', 'Start Date', required: true);The getDisplayValue() method returns a formatted string like 2026-03-26 14:30.
Optional Variants
Each primitive type has a nullable variant for optional values. The key difference: the default value is null, and the editor supports clearing the field.
// Optional string -- allows null
b.optionalText('subtitle', 'Subtitle');
// Optional integer -- allows null
b.optionalInteger('maxRetries', 'Max Retries');
// Optional double -- allows null
b.optionalDecimal('discount', 'Discount %');
// Optional boolean -- three-state: true, false, null
b.optionalBoolean('override', 'Override Default');
// Optional DateTime -- allows null
b.optionalDateTime('expiresAt', 'Expiration Date');Optional properties provide convenience getters with fallback values:
OptionalStringProperty prop = ...;
String value = prop.stringValue; // returns '' if null
OptionalIntProperty prop = ...;
int value = prop.intValue; // returns 0 if null
OptionalDoubleProperty prop = ...;
double value = prop.doubleValue; // returns 0.0 if nullEnumProperty<T>
For selecting from a list of typed options. The type T can be any Dart type -- a Dart enum, a String, an int, or a custom class.
enum CourseLevel { beginner, intermediate, advanced }
final level = EnumProperty<CourseLevel>(
key: 'level',
label: 'Course Level',
options: [
EnumOption(CourseLevel.beginner, 'Beginner',
description: 'No prerequisites'),
EnumOption(CourseLevel.intermediate, 'Intermediate'),
EnumOption(CourseLevel.advanced, 'Advanced'),
],
defaultValue: CourseLevel.beginner,
);Using the builder:
b.enumeration<CourseLevel>('level', 'Course Level',
options: [
EnumOption(CourseLevel.beginner, 'Beginner'),
EnumOption(CourseLevel.intermediate, 'Intermediate'),
EnumOption(CourseLevel.advanced, 'Advanced'),
],
defaultValue: CourseLevel.beginner,
);Auto-Registration
EnumProperty automatically registers a JsonConverter<T> for the enum type on construction if one does not already exist. This means you do not need to call PropertySystem.register<CourseLevel>(converter: ...) manually.
EnumOption<T>
Each option has:
| Field | Type | Description |
|---|---|---|
value | T | The typed value |
title | String | Display label |
description | String? | Optional tooltip or subtitle |
ListProperty<T>
For ordered lists of typed values. Supports add, remove, reorder, and per-item editing.
final prerequisites = ListProperty<String>(
key: 'prerequisites',
label: 'Prerequisites',
defaultValue: [],
required: true,
minItems: 1,
maxItems: 10,
);Using the builder:
b.list<String>('prerequisites', 'Prerequisites',
required: true,
minItems: 1,
maxItems: 10,
);List Operations
ListProperty<T> provides collection operations beyond basic value get/set:
final list = ListProperty<String>(key: 'tags', label: 'Tags');
list.add('flutter');
list.add('dart');
list.insert(0, 'mobile');
list.removeAt(1);
list.move(0, 2); // reorder
list.replaceAt(0, 'web');
list.clear();
// Access the list control for streaming
list.listControl.valueChanges.listen((items) => print(items));
list.listControl.itemControls; // per-item PropertyControl<T>PropertyListControl<T>
The listControl property exposes a PropertyListControl<T> abstraction that wraps reactive_forms.FormArray<T>:
| Method | Description |
|---|---|
items | Current list of values |
length | Number of items |
valueChanges | Stream of list changes |
add(item) | Append an item |
removeAt(index) | Remove by index |
insert(index, item) | Insert at position |
move(old, new) | Reorder items |
clear() | Remove all items |
replaceAt(index, item) | Replace at position |
itemControls | Per-item PropertyControl<T> list |
UnionProperty
For selecting one property from multiple alternatives. The control holds the selected key as a String, while each option contains a full Property for its own value.
final scheduling = UnionProperty(
key: 'scheduling',
label: 'Scheduling Mode',
defaultSelectedKey: 'fixed',
options: [
UnionOption(
key: 'fixed',
title: 'Fixed Schedule',
property: StringProperty(
key: 'fixedDate', label: 'Date', required: true,
),
),
UnionOption(
key: 'flexible',
title: 'Flexible',
property: IntProperty(
key: 'flexDays', label: 'Days to Complete', defaultValue: 30,
),
),
UnionOption(
key: 'selfPaced',
title: 'Self-Paced',
property: BoolProperty(
key: 'hasMentoring', label: 'With Mentoring', defaultValue: false,
),
),
],
);UnionOption
Each union option has:
| Field | Type | Description |
|---|---|---|
key | String | Unique identifier for this option |
title | String | Display label |
description | String? | Optional description |
property | Property | The property to edit when selected |
icon | Widget? | Optional icon widget |
metadata | Map<String, dynamic>? | Arbitrary metadata |
Union Operations
// Get current selection
String key = scheduling.selectedKey;
Property? prop = scheduling.selectedProperty;
UnionOption? opt = scheduling.selectedOption;
// Change selection
scheduling.selectOption('flexible');JSON Format
UnionProperty serializes as:
{
"selectedKey": "fixed",
"selectedValue": "2026-04-01"
}ReadOnlyProperty<T>
For display-only values that cannot be edited through the UI. Useful for computed values, system fields, or audit information.
final createdBy = ReadOnlyProperty<String>(
key: 'createdBy',
label: 'Created By',
defaultValue: 'admin',
);Using the builder:
b.readonly<String>('createdBy', 'Created By', defaultValue: 'admin');Custom Formatting
ReadOnlyProperty supports a custom formatter function:
ReadOnlyProperty<DateTime>(
key: 'createdAt',
label: 'Created',
defaultValue: DateTime.now(),
formatter: (dt) => '${dt.day}/${dt.month}/${dt.year}',
);Default formatting: DateTime values are formatted as local date/time strings, double values use toStringAsFixed(2), and all others use toString().
Common Property Parameters
All property types share these parameters from Property<T>:
| Parameter | Type | Description |
|---|---|---|
key | String | Unique identifier within the collection |
label | String | Display label for the editor |
defaultValue | T | Initial value |
help | String? | Help text shown below the editor |
group | String? | Group identifier for organizing into sections |
required | bool | Whether the property must have a value |
validators | List<PropertyValidator> | Validation rules |
visibleCondition | PropertyCondition? | When to show this property |
enabledCondition | PropertyCondition? | When to enable this property |
customKey | String? | Custom editor/converter key for registry lookup |
metadata | Map<String, dynamic>? | Arbitrary metadata |
Next Steps
- Collections -- Group properties with the builder and editor
- Conditions -- All 12 condition types
- Validation -- Validators in detail