Compatibility between SDC and the Form API

Created on 17 December 2024, 4 months ago

Problem/Motivation

SDC doesn't play well with the Form API:

  • we can put a full form into a component slot, but we can't put a form element of a form defined outside the component
  • we can't define form element, directly usable with the Form API, with SDC. So we can't easily implement some design systems components like https://getbootstrap.com/docs/5.3/forms/checks-radios/#switches

This ticket is focused on the first issue, but let's keep the second one in mind.

Restriction of a chat between @pminf @mmbk & @pdureau: https://drupal.slack.com/archives/C4EDNHFGS/p1734453836627559

While processing a form the FormBuilder handles only children, returned by Element::children($element) Render elements located in #slots are not processed, so they won't get the meta data that are necessary to process the input field, I hacked around that problem by adding the select field a top-level element of the component and added a preRenderCallback to the SDC that is moving the select field into the slot.

This may be the same issue as the one with table render element.

Proposed resolution

Is it possible to merge #slots and #props into Element::children()

For example:
<code>#type: component
#component: 'provider:foo'
#slots:
  slot_1: {}
  slot_2: {}
#props:
  prop_1: ''
  prop_2: ''

Would become:

 #type: component
#component: 'provider:foo'
slot_1: {}
slot_2: {}
prop_1: ''
prop_2: ''

There is no risk in merging slots & props because they already share the same namespace as Twig template variables.

But it may be not as easy and safe as adapting the form API to this special case. And fixing this at the form API level can also help us to fix the similar cases (like table for example)

API changes

Maybe. Let's be careful.

πŸ“Œ Task
Status

Active

Version

11.1 πŸ”₯

Component

single-directory components

Created by

πŸ‡«πŸ‡·France pdureau Paris

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @pdureau
  • πŸ‡«πŸ‡·France pdureau Paris
  • πŸ‡³πŸ‡ΏNew Zealand quietone

    Changes are made on on 11.x (our main development branch) first, and are then back ported as needed according to the Core change policies β†’ .

  • πŸ‡«πŸ‡·France pdureau Paris
  • πŸ‡«πŸ‡·France pdureau Paris
  • πŸ‡«πŸ‡·France pdureau Paris
  • Assigned to Grimreaper
  • πŸ‡«πŸ‡·France Grimreaper France πŸ‡«πŸ‡·
  • πŸ‡¨πŸ‡¦Canada Charlie ChX Negyesi 🍁Canada

    (if you need form API assistance message chx on Drupal Slack. Response times should be below 24 hours but usually below 4 hours.)

  • Pipeline finished with Canceled
    about 2 months ago
    Total: 80s
    #438105
  • πŸ‡«πŸ‡·France Grimreaper France πŸ‡«πŸ‡·

    Hello,

    @ghost of drupal past, thanks for the proposal.

    First POC, trying to tell Element::children to got looking into #slots if the element is a component make the form element inside the component to be prepared by the Form API, but:

    1. It remains duplicated on rendering (one textfield outside the component, one inside)
    2. The 2 elements have the same name attribute, so when submitting the form it is the element in the component which value is retrieved but I think it i only a side effect of having duplicated name.
    3. "parent" mechanism in the form API may be confused/malformed.

    So next step will be to try to put slots as component element child and so adapt SDC (and later table element too).

  • πŸ‡«πŸ‡·France pdureau Paris

    But previous results makes this approach very side effect prone.

    Yes, that sounds risky, but it worth to check.

  • Pipeline finished with Canceled
    26 days ago
    Total: 66s
    #460891
  • Pipeline finished with Canceled
    25 days ago
    Total: 32s
    #461781
  • Pipeline finished with Failed
    24 days ago
    Total: 151s
    #462559
  • Pipeline finished with Canceled
    24 days ago
    #462639
  • Pipeline finished with Canceled
    23 days ago
    Total: 33s
    #463178
  • Pipeline finished with Canceled
    23 days ago
    #463195
  • Pipeline finished with Canceled
    23 days ago
    #463499
  • πŸ‡«πŸ‡·France G4MBINI BΓ¨gles
  • Pipeline finished with Canceled
    21 days ago
    Total: 70s
    #465727
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Following, I wrote a number of form components for ui_suite_uswds but really serves no purpose :(

  • πŸ‡«πŸ‡·France pdureau Paris

    Following, I wrote a number of form components for ui_suite_uswds but really serves no purpose :(

    They will be usable once πŸ“Œ Define form elements from SDC Active is done.

    We are actively working on both issues and we already have very promising results.

  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    I think I did use the checkbox component for uswds in the checkbox.html.twig file but it was messy. SO yay to here that!

  • Pipeline finished with Canceled
    14 days ago
    Total: 71s
    #471568
  • πŸ‡«πŸ‡·France Grimreaper France πŸ‡«πŸ‡·
  • πŸ‡«πŸ‡·France Grimreaper France πŸ‡«πŸ‡·

    Yesterday session is online: https://www.youtube.com/live/6AvlzYN17Rs?t=25741s

    Until presentation support is posted somewhere you can go give a look.

    From @nod_ feedbacks, I am:
    - creating another branch with containing only core changes.
    - creating a dedicating plugin instead of altering ComponentElement
    - need to find a way to make submitted values work without using #name

  • Pipeline finished with Failed
    8 days ago
    Total: 89s
    #475736
  • Pipeline finished with Canceled
    8 days ago
    Total: 78s
    #475740
  • πŸ‡«πŸ‡·France Grimreaper France πŸ‡«πŸ‡·

    In MR https://git.drupalcode.org/project/drupal/-/merge_requests/11866, I removed what is only for πŸ“Œ Define form elements from SDC Active so that in this issue, we can focus only on SDC and Form API compatibility.

  • Pipeline finished with Failed
    7 days ago
    Total: 160s
    #476447
  • Pipeline finished with Canceled
    7 days ago
    Total: 75s
    #476583
  • πŸ‡«πŸ‡·France Grimreaper France πŸ‡«πŸ‡·

    #name is not usable as it is right now because of Ajax.

    Currently poking a field widget which will be able to use components, the settings form is broken.

  • πŸ‡«πŸ‡·France Grimreaper France πŸ‡«πŸ‡·

    Ok, we found a way to get rid of the #name. Just need to ensure no numeric key.

    Before:

    $form['component_card'] = [
        '#type' => 'component',
        '#component' => 'core_sdc_form:card',
        'content' => [
          '#type' => 'component',
          '#component' => 'core_sdc_form:card_body',
          'content' => [
            [
              '#type' => 'textfield',
              '#title' => $this->t('Textfield in content'),
            ],
          ],
        ],
    ];
    

    After:

    $form['component_card'] = [
        '#type' => 'component',
        '#component' => 'core_sdc_form:card',
        'content' => [
          '#type' => 'component',
          '#component' => 'core_sdc_form:card_body',
          'content' => [
            'foo' => [
              '#type' => 'textfield',
              '#title' => $this->t('Textfield in content'),
            ],
          ],
        ],
    ];
    
  • Pipeline finished with Failed
    7 days ago
    Total: 120s
    #476783
  • Pipeline finished with Canceled
    7 days ago
    Total: 88s
    #476784
  • Pipeline finished with Canceled
    7 days ago
    Total: 32s
    #476786
  • πŸ‡¬πŸ‡§United Kingdom catch

    This is looking promising, adding various review tags.

  • πŸ‡«πŸ‡·France pdureau Paris

    This proposal is close to completion, we keep this "Needs work" until we check existing tests and add new ones.

    Most of the remaining work is happening in πŸ“Œ Define form elements from SDC Active where I am cgecking the SDC philosophy will be "respected":

    • UI only, business agnostic, logic and concepts
    • Front-dev friendly
    • Sharable and design system oriented
  • πŸ‡«πŸ‡·France Grimreaper France πŸ‡«πŸ‡·

    Demo gif in #3508641-12: Define form elements from SDC β†’ .

    Pushing current work state before cleanup.

  • Pipeline finished with Canceled
    5 days ago
    Total: 91s
    #477863
  • Pipeline finished with Failed
    5 days ago
    Total: 597s
    #477864
  • Pipeline finished with Success
    5 days ago
    Total: 546s
    #477899
  • πŸ‡«πŸ‡·France Grimreaper France πŸ‡«πŸ‡·

    With the fix from πŸ› Incorrect render structure in Navigation PageContext Active , the proposed changes in Renderer and ComponentElement do not break existing tests.

  • πŸ‡«πŸ‡·France pdureau Paris

    Grimreaper's proposal is to allow slots as children to make them work with Form API:

     #type: component
    #component: 'provider:foo'
    #props:
      prop_1: ''
      prop_2: ''
    slot_1: {}
    slot_2: {}

    And then, in ComponentElement, we move the slots to the expected position in #slots:

     #type: component
    #component: 'provider:foo'
    #props:
      prop_1: ''
      prop_2: ''
    #slots:
      slot_1: {}
      slot_2: {}

    Is it the opportunity to deprecate #slots and to promote render children as the expected way of settings slots in SDC ?

  • Pipeline finished with Failed
    4 days ago
    Total: 240s
    #478608
  • πŸ‡«πŸ‡·France Grimreaper France πŸ‡«πŸ‡·

    Problem with SDC on component with multiple inputs, solved by using [] on name in the component.

    We tried to create a lat/lon component with geofield, not working because of applicative
    logic into the field type.

    Checkbox in form API directly: OK
    Checkboxes in form API directly: OK

    Usage of names to handle multiple inputs.

    Problem of unchecked checkbox currently handled in Checkbox.php form element, workaround in field widget in UIP 2.

    TODO:
    - field storage and field setting mapping into the component
    - test checkboxes as field widget
    - test with multiple values fields in field widget
    - handle data type constraints?

  • Pipeline finished with Failed
    4 days ago
    Total: 123s
    #478707
  • Pipeline finished with Canceled
    3 days ago
    Total: 74s
    #479480
Production build 0.71.5 2024