Orbyss.Blazor.JsonForms
0.0.1
See the version list below for details.
dotnet add package Orbyss.Blazor.JsonForms --version 0.0.1
NuGet\Install-Package Orbyss.Blazor.JsonForms -Version 0.0.1
<PackageReference Include="Orbyss.Blazor.JsonForms" Version="0.0.1" />
<PackageVersion Include="Orbyss.Blazor.JsonForms" Version="0.0.1" />
<PackageReference Include="Orbyss.Blazor.JsonForms" />
paket add Orbyss.Blazor.JsonForms --version 0.0.1
#r "nuget: Orbyss.Blazor.JsonForms, 0.0.1"
#:package Orbyss.Blazor.JsonForms@0.0.1
#addin nuget:?package=Orbyss.Blazor.JsonForms&version=0.0.1
#tool nuget:?package=Orbyss.Blazor.JsonForms&version=0.0.1
π¦ Orbyss.Blazor.JsonForms
A fully .NET-native implementation of the JsonForms.io standard for schema-driven forms in Blazor.
No Angular, no web components β just C#, JSON Schema, and flexible Blazor architecture.
π― What is this?
This is the UI-agnostic core framework for rendering dynamic forms from JSON Schema in .NET. It handles:
- Form generation
- Schema interpretation
- Localization via translation schema
- Layout, validation, and data management
You plug in the UI layer. Itβs like a form engine β and you bring the renderer.
π Available UI Integrations
Use one of our ready-to-go UI packages:
Or you can build your own; for example when you have your own Blazor component system, or you are using other external frameworks such as Radzen, Telerik, or Fluent UI
π How to: Implement Your Own UI Layer
β Start by implementing the following interface
public interface IFormComponentInstanceProvider
{
InputFormComponentInstanceBase GetInputField(IJsonFormContext context, FormControlContext control);
IFormComponentInstance GetGridRow(IFormElementContext? row);
IFormComponentInstance GetGridColumn(IFormElementContext? column);
IFormComponentInstance GetGrid(IJsonFormContext? form, FormPageContext? page);
ButtonFormComponentInstanceBase GetButton(FormButtonType type, IJsonFormContext? form);
NavigationFormComponentInstanceBase GetNavigation(IJsonFormContext formContext);
ListFormComponentInstanceBase GetList(FormListContext? list = null);
ListItemFormComponentInstance GetListItem(IFormElementContext? listItem = null);
}
Example of a GetInputField implementation:
public virtual InputFormComponentInstanceBase GetInputField(IJsonFormContext context, FormControlContext control)
{
var type = control.Interpretation.ControlType;
return type switch
{
ControlType.Boolean => GetBooleanField(control),
ControlType.String => GetTextField(control),
ControlType.Enum => GetDropDownField(control),
ControlType.EnumList => GetMultiDropDownField(control),
ControlType.DateTime => GetDateTimeField(control),
ControlType.DateOnly => GetDateOnlyField(control),
ControlType.DateOnlyUtcTicks => GetDateUtcTicksField(control),
ControlType.DateTimeUtcTicks => GetDateTimeUtcTicksField(control),
ControlType.Integer => GetIntegerField(control),
ControlType.Number => GetNumberField(control),
_=> throw new NotSupportedException($"Cannot create an input field for type '{type}'")
};
}
π§± Step-by-Step Guide to Building a Custom Component
β 1. Create your Razor input component
<SfTextBox Type=InputType.Number
CssClass="@FullClass"
Enabled=@(!Disabled)
Readonly=ReadOnly
Value="@Value"
Placeholder="@Label"
FloatLabelType="FloatLabelType.Always"
ID="@id"
ValueChanged="@ValueChangedHandler"
ShowClearButton=@Clearable
Width="@Width" />
@if (HasError)
{
<div class="e-error validation-message">@ErrorHelperText</div>
}
else if (!string.IsNullOrWhiteSpace(HelperText))
{
<div class="validation-message "><i>@HelperText</i></div>
}
Add these standard parameters:
[Parameter] public string? Label { get; internal set; }
[Parameter] public bool Disabled { get; internal set; }
[Parameter] public bool ReadOnly { get; internal set; }
[Parameter] public string? ErrorHelperText { get; internal set; }
[Parameter] public string? HelperText { get; set; }
// Required: runtime error thrown when not specified
[Parameter] public string Value { get; set; }
// Required: runtime error thrown when not specified
[Parameter] public EventCallback<string> ValueChanged { get; set; }
β οΈ If you forget to invoke ValueChanged, your input wonβt update the form state! β οΈ The control types are fixed. You must return the right Value/ValueChanged<T> pair for each field type. See the table below.
public static class ControlTypeLookup
{
public static readonly Type Enum = typeof(string);
public static readonly Type EnumList = typeof(IEnumerable<string>);
public static readonly Type DateTime = typeof(DateTime?);
public static readonly Type DateTimeUtcTicks = typeof(DateTimeUtcTicks?);
public static readonly Type DateOnly = typeof(DateOnly?);
public static readonly Type DateOnlyUtcTicks = typeof(DateUtcTicks?);
public static readonly Type Number = typeof(double?);
public static readonly Type Integer = typeof(int?);
public static readonly Type String = typeof(string);
public static readonly Type Boolean = typeof(bool);
public static Type GetForControlType(ControlType controlType) => fieldsPerControlType[controlType];
}
Example: If your schema field is "type": "integer", your component must have:
[Parameter] public int? Value { get; set; }
[Parameter] public EventCallback<int?> ValueChanged { get; set; }
β 2. Create a component instance class
This class represents the contract of your component, and is used internally to map component parameters from the IFormComponentInstanceProvider implementation to your razor components. When the standard parameters are sufficient for your components, you can simply make use of our built-in instances:
public virtual ListItemFormComponentInstance GetListItem(IFormElementContext? listItem = null)
{
return new ListItemFormComponentInstance<SyncfusionFormListItem>();
}
If the built-in component instances do not provide all the parameters you need for your own components, you will have to derive from one of the (base)classes and add your own parameters.
Custom razor component:
<SfSwitch HtmlAttributes=@htmlAttributes
Checked="@Value"
CssClass="@Class"
TChecked="bool"
CheckedChanged="OnValueChanged"
Disabled=@(Disabled || ReadOnly)
OffLabel="@OffLabel"
OnLabel="@OnLabel" />
[Parameter]
public string? OnLabel { get; set; }
[Parameter]
public string? OffLabel { get; set; }
Custom component instance:
public class MyCustomSwitchInstance : InputFormComponentInstance<MyCustomSwitch>
{
public MyCustomSwitchInstance() : base(t => (bool?)t)
{
}
public string? OnLabel { get; set; }
public string? OffLabel { get; set; }
protected override IDictionary<string, object?> GetFormInputParameters()
{
return new Dictionary<string, object?>
{
[nameof(MyCustomSwitch.OffLabel)] = OffLabel,
[nameof(MyCustomSwitch.OnLabel)] = OnLabel
};
}
}
β 3. Return your instance
protected virtual InputFormComponentInstanceBase GetBooleanField(FormControlContext control)
{
var booleanControlType = control.Interpretation.GetOption("custom-bool-type");
if($"{booleanControlType}" == "switch")
{
return new MyCustomSwitchInstance();
}
else
{
return new SyncfusionCheckboxInstance();
}
}
π‘ You can make use of (custom) options that you can configure in your UI Schema. See jsonforms.io docs
π How The Framework Works
The framework generates forms using three different schemas:
Schema Type | Description |
---|---|
JSON Schema | Defines the data structure (types, enums, etc.) |
UI Schema | Controls layout, grouping, (custom) options, rules |
Translation Schema | Provides localized labels, errors, and enums |
Example:
// JSON Schema
{
"type": "object",
"properties": {
"firstName": {
"type": "string",
"minLength": 21
},
"surname": {
"type": "string"
}
},
"required":[
"firstName"
]
}
// UI Schema
{
"type": "VerticalLayout",
"elements": [
{
"type": "Control",
"scope": "#/properties/firstName"
},
{
"type": "Control",
"scope": "#/properties/surname",
"options": {
"hidden": true
},
"rule":{
"effect": "Show",
"condition":{
"scope": "#/properties/firstName",
"schema":{
"minLength": 2
}
}
}
}
],
"options": {
"customOption": "custom-option-value"
}
}
// Translation Schema
{
"resources": {
"en": {
"translation": {
"firstName": {
"label": "First Name",
"error":{
"minLength": "Must have minimum of 21 characters"
}
},
"surname": {
"label": "Surname"
},
"customLabel": "Special"
}
},
"nl": {
"translation": {
"firstName": {
"label": "Voornaam",
"error":{
"minLength": "Moet minimaal 21 karakters bevatten"
}
},
"surname": {
"label": "Achternaam"
},
"customLabel": "Speciaal"
}
}
}
}
π¦ Installation
dotnet add package Orbyss.Components.JsonForms
Then reference a UI implementation package or build your own.
π License
MIT License Β© Orbyss
π Links
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- JLio.Client (>= 1.2.1)
- Newtonsoft.Json.Schema (>= 4.0.1)
- Orbyss.Components.Json.Models (>= 1.0.0)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Orbyss.Blazor.JsonForms:
Package | Downloads |
---|---|
Orbyss.Blazor.Syncfusion.JsonForms
Syncfusion UI-based renderer for the Orbyss.Blazor.JsonForms form generation engine β a fully .NET-native schema-driven forms framework built on JsonForms.io concepts. |
|
Orbyss.Blazor.MudBlazor.JsonForms
MudBlazor UI-based renderer for the Orbyss.Blazor.JsonForms form generation engine β a fully .NET-native schema-driven forms framework built on JsonForms.io concepts. |
GitHub repositories
This package is not used by any popular GitHub repositories.