Skip to content

Spike: Evaluate form libraries #358

Closed
Closed

Description

@lornakelly

Description

Spike for ref:
#337

Evaluate available form libraries to determine the best fit for implementing dynamic task configuration forms. The selected library must support schema-driven form generation.

Motivation

To build a robust and maintainable dynamic form system for task configuration, we need to select a form library that aligns with our technical requirements and provides the flexibility needed to support all Open Workflow task types

Proposed Implementation

No response

Definition of Done

  • Implementation: Fully implemented according to the Open Workflow spec.
  • Unit Tests: Comprehensive unit tests are included and passing.
  • Integration Tests: Verified within the monorepo and target environments (Web/VS Code).
  • Documentation: Updated README.md, ADRs, or official docs.
  • Performance: No significant regression in editor responsiveness.
  • Accessibility: UI changes comply with accessibility standards.

Activity

  1. self-assigned this
    on Aug 25, 2026
  2. added theissue type on Aug 25, 2026
  3. lornakelly commented on Aug 26, 2026

    @lornakelly
    CollaboratorAuthor

    Context

    Building on #337, we need a library to hold form state for the node-editing side panel - consuming the resolved schemas from filterSchemaByDefinition.ts and rendering through our existing src/components/ui/* components.

    Option A: react-jsonschema-form (RJSF)

    Main Pros

    • Generates a working form layout from JSON schemas with almost zero upfront code.
    • Handles open maps (additionalProperties) out of the box (add, rename, and remove actions).

    Main Cons

    Two options were evaluated to see if it would work with our existing shadcn components for the form:

    1. @rjsf/shadcn:

      RJSF site links to the @rjsf/shadcn theme package but it is unusable in our project because it ships un-prefixed Tailwind styles, whereas our application monorepo build exclusively targets dec: utility styles as it is embedded in host applications. It also vendors its own copy of 14 shadcn primitives so we would have 2 component sets in one app

    2. withTheme()

    • Because @rjsf/shadcn is ruled out, it means we would have to use the generic withTheme() HOC API. Simple inputs map fine, but compound controls like Combobox do not against RJSF's flat value/onChange widget contract. The friction grows with every non-trivial control we add, and it lands hardest on the ones we need most.

    Other reasons to not adopt:

    • We don't own the render cycle. RJSF holds the form state and decides which fields exist, in what order, and when they update - we fill slots it calls rather than deciding what to render.
    • Very limited when it comes to UX - UX customisation runs through RJSF's own contracts - uiSchema plus template overrides. Neither lets us change which fields render or how deep, and there is no collapsing support at all.
    • No out of the box dirty state so managing Save/Cancel UI triggers requires building a custom, manual deep-diffing engine

    Option B: Uniforms

    Ruled out:

    • No pre-built theme for shadcn/ui or Base UI, so we would design, code and maintain a wrapper for every primitive.
    • I used setTask as the baseline test, it cannot render the field that matters. Uniforms has no field type for open maps, so set - the Set task's only required property - gets a label and no control. We would need to build a workaround for this that would not be straightforward

    Option C: React Hook Form (RHF) — RECOMMENDED

    Main Pros

    • We own the render cycle. We retain complete architectural control over what renders, in what order, and how deep the form cascades
    • We can implement the UX we want - collapsing sections, progressive disclosure, conditional fields - in our own interaction logic rather than in schema syntax.
    • Native tracking for isDirty and dirtyFields is available out of the box
    • Fits our UI components directly with no intermediate theme abstraction layers, prefix mapping workarounds, or compound component layout friction as it is the recommended form library for shadcn
    • Client-side validation hooks into the SDK's existing Ajv engine, so the side panel and the canvas error badges cannot disagree.
    • No Zod needed. The shadcn docs use Zod in their examples, but it isn't required - the POC runs without it against the setTask output from the WIP filterSchemaByDefinition, and works well.
    • Less risk as we move forward - shadcn officially have it as an option on site.

    Main Cons

    • We must write and maintain our own custom recursive field routing loop (This is the one layout element RJSF handles for free)
    • No open-map or array handling out of the box - we build those, RHF renders nothing by design, so this is true of every control, and it is not too much work to cater for.

    Small POC to prove we can use react-hook-form to dynamically build a form without Zod, rendering the JSON the WIP filterSchemaByDefinition produces, without hardcoding fields:

    https://github.com/lornakelly/editor/tree/form-library-poc

    NOTE: I just have all props render as a simple Input, and hardcoded the setTask JSON that was generated from the filter. You can view it in DynamicSchemaForm.stories and read the docs there.

  4. handreyrc commented on Aug 27, 2026

    @handreyrc
    Contributor

    @lornakelly,

    I tested your PoC and it LGTM! It is definitely a good starting point.
    I agree that option C is the way to go, mainly because shadcn officially has it and it aligns with our stack.
    However, we are bringing a certain level of complexity to build a proper form on the editor side. That being said, we shall put in extra effort to not couple the form to the schema structure and its definitions, as it may change over time.

    Thanks for your analysis!

  5. lornakelly commented on Aug 27, 2026

    @lornakelly
    CollaboratorAuthor

    Agreed on both counts. That's the trade, and it's the main con, we write the field routing that RJSF would give us for free but get much more control and dont have to fight with UX and implement other functionality that comes out of the box with rhf. UX will be very important for us as well especially with the amount of nested objects

    Thanks @handreyrc

  6. cheryl7114 commented on Aug 27, 2026

    @cheryl7114
    Contributor

    Just tested the POC, looks really good. I agree on going with option C - although being more complex, it seems like the pros outweigh the cons compared to the other options

  7. fantonangeli commented on Aug 27, 2026

    @fantonangeli
    Member

    @lornakelly I can agree with Option C, but I have a few points to share.
    I also tested your PoC and it LGTM

    Option A: react-jsonschema-form (RJSF)

    I see RJSF has UI options that let us control the order of the inputs:
    https://rjsf-team.github.io/react-jsonschema-form/
    There is an ORDERING example on the left which uses:

      "ui:order": [
        "firstName",
        "lastName",
        "*",
        "password"
      ],
    

    We also have "ui:widget": "hidden" to hide some fields and support only specific fields for editing.

    Regarding the CSS prefix, this does seem to be an issue, as I couldn't find any documented configuration for it.

    Option B: Uniforms

    +1 to prefer Option A over this one, as with Uniforms we would have to implement our own fields. This is not particularly complex, but RJSF seems to offer more out of the box.

    From my previous experience with Uniforms in another project, we customised it to use a different UI library. The full customisation required 27 .tsx files, but they were neither long nor particularly complex.

    Option C: React Hook Form (RHF)

    IIUC, this means that initially we would support editing only a specific subset of fields, rather than all fields, while using the schema for validation. Is that correct?

    What I like about this approach is that we go for "baby steps"


    +1 also to @handreyrc's comment about avoiding too much complexity for this feature, at least at the beginning. Option C seems better aligned with this direction.

    I still think this spike and the alternatives we evaluated are important to keep documented, in this spike, for future reference.

  8. lornakelly commented on Aug 27, 2026

    @lornakelly
    CollaboratorAuthor

    Thanks @fantonangeli

    I can see that I overstated the ordering as a con. Ultimately RHF will give is more flexibility from a UX perspective and is more in line with our stack.

    Agree on the baby steps as well, one issue at a time. Yes we start with a subset and grow it with validation coming from the sdk. +1 on keeping this documenting in spike for future

    Looks like agreement with Option C anyway so we will go with that

  9. kumaradityaraj commented on Aug 28, 2026

    @kumaradityaraj
    Contributor

    +1 for React Hook Form as it seems like the best fit here since it gives us full control over rendering and UX while integrating cleanly with our existing components.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions