Orbyss.Blazor.JsonForms 1.0.3

dotnet add package Orbyss.Blazor.JsonForms --version 1.0.3
                    
NuGet\Install-Package Orbyss.Blazor.JsonForms -Version 1.0.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Orbyss.Blazor.JsonForms" Version="1.0.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Orbyss.Blazor.JsonForms" Version="1.0.3" />
                    
Directory.Packages.props
<PackageReference Include="Orbyss.Blazor.JsonForms" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Orbyss.Blazor.JsonForms --version 1.0.3
                    
#r "nuget: Orbyss.Blazor.JsonForms, 1.0.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Orbyss.Blazor.JsonForms@1.0.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Orbyss.Blazor.JsonForms&version=1.0.3
                    
Install as a Cake Addin
#tool nuget:?package=Orbyss.Blazor.JsonForms&version=1.0.3
                    
Install as a Cake Tool

πŸ“¦ 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, also called the 'FormComponentInstanceProvider'. This library is the form engine β€” and you must bring the renderer.

With an implemented UI layer, you can render the JsonForms in your code as follows:

<JsonForm InitOptions=@options/>

@code{
    JsonFormContextInitOptions options = new(
        jsonSchema,
        uiSchema,
        translationSchema
    );
}

❗You can specify JsonFormContext as parameter, or as a Transient Service (DI)

❗You can specify ComponentInstanceProvider as parameter, or as a DI service

❗You can provide the following cascading values to your JsonForm: "Language, Disabled, ReadOnly".


πŸš€ 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="@OnValueChanged"
           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> OnValueChanged { get; set; }

⚠️ If you forget to invoke OnValueChanged, your input won’t update the form state!

⚠️ The control types are fixed. You must return the right Value/OnValueChanged<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?> OnValueChanged { 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

🀝 Contributing

This project is open source and contributions are welcome!

Whether it's bug fixes, improvements, documentation, or ideas β€” we encourage developers to get involved.
Just fork the repo, create a branch, and open a pull request.

We follow standard .NET open-source conventions:

  • Write clean, readable code
  • Keep PRs focused and descriptive
  • Open issues for larger features or discussions

No formal contribution guidelines β€” just be constructive and respectful.


⭐️ If you find this useful, give us a star and help spread the word!

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.

Version Downloads Last Updated
1.0.3 232 8/7/2025
1.0.2 211 8/7/2025
1.0.1 205 8/6/2025
1.0.0 205 8/6/2025
0.0.1 190 8/4/2025

*Release: 8 August, 2025*
- Found minor bug in TranslationContext; when language was null, the property name for labels was returned right away.
Now, we will first check if there are any translations, and only when there is not other option left will we return the property name