Update XB's `image` SDC to comply with best practices, and document those best practices

Created on 19 August 2024, 4 months ago
Updated 28 August 2024, 4 months ago

Overview

See #3467972-13: Unable to save node article form โ€” remove obsolete TwoTerribleTextAreasWidget + fix duplicate `XB:image` SDC โ†’ .

components/image/image.component.yml was added long ago, in 795f4db30, on April 26, before DrupalCon Portland โ€” see https://wimleers.com/xb-week-5.

Some would argue it is unnecessarily nested, and @pdureau certainly has done that at #3446722-29: Introduce an example set of representative SDC components; transition from "component list" to "component tree" โ†’ :

$refs resolution don't seem to work yet in Experience Builder, so the component was not fully tested, but the component template is surprising:

<img src="{{ image.src }}" alt="{{ image.alt }}" width="{{ image.width }}" height="{{ image.height }}"></img>    

What is the purpose of this component?

  • it has a single prop, also called "image", so the component looks like a meaningless wrapper around this single prop
  • it doesn't use the expected attributes object
  • no HTML classes (and the component has no dedicated CSS), so no specific UI purpose
  • it is nothing more than a rigid HTML element, like an image renderable but less powerful because with hardcoded attributes (so not compatible with lazy loading or any API working with images)

Am I missing something?

Proposed resolution

TBD

User interface changes

TBD

๐Ÿ“Œ Task
Status

Needs review

Component

Page builder

Created by

๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

Live updates comments and jobs are added and updated live.
  • Needs product manager review

    It is used to alert the product manager core committer(s) that an issue represents a significant new feature, UI change, or change to the "user experience" of Drupal, and their signoff is needed. If an issue significantly affects the usability of Drupal, use Needs usability review instead (see the governance policy draft for more information).

Sign in to follow issues

Comments & Activities

  • Issue created by @wim leers
  • Status changed to Needs review 4 months ago
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    ๐Ÿ‘‹ @pdureau โ€” time to finally respond in detail to what you wrote on August 1!

    • it has a single prop, also called "image", so the component looks like a meaningless wrapper around this single prop

    Why is that meaningless?

    When is it appropriate to use nested key-value pairs?

    Not being an SDC expert, I think the current structure of components/image/image.component.yml makes sense: the image property fully encapsulates all concerns/semantics of what "an image" constitutes.

    • it doesn't use the expected attributes object

    If this is expected, then why isn't this imposed by SDC? ๐Ÿค”

    • no HTML classes (and the component has no dedicated CSS), so no specific UI purpose

    Correct, this is meant to be one of the "elements" (see 1.1 Elements in the product requirements).

    IOW: this is intended to be a building block in other components.

    • it is nothing more than a rigid HTML element, like an image renderable but less powerful because with hardcoded attributes (so not compatible with lazy loading or any API working with images)

    That's a good argument to add an attributes property in this particular case, but why is that generically true?

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ
  • ๐Ÿ‡ซ๐Ÿ‡ทFrance pdureau Paris

    attributes object

    If this is expected, then why isn't this imposed by SDC? ๐Ÿค”
    That's a good argument to add an attributes property in this particular case, but why is that generically true?

    It is the other way around. Every component template has an attributes object automatically injected.

    Its is good practice to use this already available attributes object in the template:

    • because he can be leverage by some API or mechanism, which are injecting class utilities, attributes used by display builders, ARIA attributes for accessibility, semantic annotation (RDFa, schema.org...), SEO tagguing, JS events.... without duplications of attributes
    • it is a more elegant way to allow the injection custom classes than a extra_classes array of strings prop, because it also checks duplicates

    However, I believe this attributes can be even better by allowing #attributes key alongside #props["attributes"], and I may create a Core issue as soon as UI Patterns 2.0 is released.

    Image component and image prop

    Why is that meaningless?
    When is it appropriate to use nested key-value pairs?

    Because the full component and its single prop are the exact same thing :

    name: Image
    props:
      type: object
      properties:
        image: 
        title: image
          type: object
          required:
          - src
          properties:
            src:
              title: Image URL
              "$ref": json-schema-definitions://experience_builder.module/image-uri
            alt:
              title: Alternative text
              type: string
            width:
              title: Image width
              type: integer
            height:
              title: Image height
              type: integer
    

    With:

    <img src="{{ image.src }}" alt="{{ image.alt }}" width="{{ image.width }}" height="{{ image.height }}"></img>
    

    It says something about the architecture. So we have a layer, the image component or the image prop, which is not expected here.

    If we remove the prop, we get that:

    name: Image
    props:
      type: object
      required:
      - src
      properties:
        src:
          title: Image URL
          "$ref": json-schema-definitions://experience_builder.module/image-uri
        alt:
          title: Alternative text
          type: string
        width:
          title: Image width
          type: integer
        height:
          title: Image height
          type: integer
    

    With:

    <img src="{{ src }}" alt="{{ alt }}" width="{{ width }}" height="{{ height }}"></img>
    

    But we can remove the component instead, as proposed in the next section.

    HTML elements as SDC components

    Correct, this is meant to be one of the "elements" (see 1.1 Elements in the product requirements).
    IOW: this is intended to be a building block in other components.

    Indeed, we need HTML elements renderables which are lighter than components:

    • no templates, no predefined attachments
    • no props and slots but the standardized #attributes and the element content

    Oh wait, we have this already ๐Ÿ˜‰

    [
        '#type' => 'html_tag',
        '#tag' => 'p',
        '#value' => $this->t('Hello World'),
        '#attributes' => [
          'foo' => 'bar',
          'height' => 50,
        ],
    ];
    

    https://git.drupalcode.org/project/drupal/-/blob/11.x/core/lib/Drupal/Co...

    No need to create a SDC component for each HTML elements, like:

    <img src="{{ src }}" alt="{{ alt }}" width="{{ width }}" height="{{ height }}"></img>
    

    No need to create a generic HTML element as a SDC component with:

    <{{ html_tag }}{{attributes}}>{{ content }}</{{ html_tag }}>
    

    Because HTML elements are not component. They don't have a design system meaning. We don't want to have them in the component libraries, we don't want them to show in component selectors, we don't want to load the full SDC API to render them.

    Not every renderable must become a SDC component. I know, it is tempting, with such a great hammer, everything looks like a nail.

    HTML elements, Icons (see https://www.drupal.org/project/ui_icons โ†’ ), Inline Templates, Plain Text... are renderables but not components. And we will discover more on our journey to design system implementations.

    So, maybe Experience Builder needs to handle non-SDC renderables in slots. For example, a WYSIWYG for #markup;

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    It is the other way around. Every component template has an attributes object automatically injected.

    TIL. But my question still stands, albeit differently: why doesn't SDC then not complain about this Twig template not printing the attributes variable at all?

    Indeed, we need HTML elements renderables which are lighter than components:

    • no templates, no predefined attachments
    • no props and slots but the standardized #attributes and the element content

    Oh wait, we have this already ๐Ÿ˜‰

    This is not the way @lauriii has been talking about "elements" (during https://wimleers.com/xb-week-5#chaos-origin). He's been referring to them as a carefully curated set of SDCs, tagged/categorized as "elements".

    IOW: "elements" !== "HTML elements".

    So, maybe Experience Builder needs to handle non-SDC renderables in slots. For example, a WYSIWYG for #markup;

    We need a WYSIWYG to be able to provide HTML markup that goes into a prop. See ๐Ÿ“Œ [later phase] `StringSemanticsConstraint::MARKUP`: agree how SDC prop JSON schema can convey it should be markup, and allow using CKEditor 5 Needs review โ€” I bet you'll want to chime in on that issue too :)

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    WRT definition of "elements" โ€” see discussion at ๐Ÿ“Œ Clarify "components" vs "elements" vs "patterns" Active , there's no definitive answer yet.

  • ๐Ÿ‡ซ๐Ÿ‡ทFrance pdureau Paris

    TIL. But my question still stands, albeit differently: why doesn't SDC then not complain about this Twig template not printing the attributes variable at all?

    SDC is currently not validating the component templates. It doesn't check used by undefined slots or props, it doesn't check defined but unused slots or props.

    ui_patterns_devel module has a drush command to do such checks. I hope it will be useful and appreciated by the SDC community.

    This is not the way @lauriii has been talking about "elements" (during https://wimleers.com/xb-week-5#chaos-origin). He's been referring to them as a carefully curated set of SDCs, tagged/categorized as "elements".

    IOW: "elements" !== "HTML elements".

    OK. Do you have an example of such ? Maybe https://git.drupalcode.org/issue/experience_builder-3446722/-/tree/exper... is not a good one, because this one is clearly an HTML element.

    We need a WYSIWYG to be able to provide HTML markup that goes into a prop. See #3467959: `StringSemanticsConstraint::MARKUP`: agree how SDC prop JSON schema can convey it should be markup, and allow using CKEditor 5 โ€” I bet you'll want to chime in on that issue too :)

    Of course I will add a comment on this issue ;)

    I enjoy our conversation, but I am also surprised we (Experience Builder team & UI Suite team) have different understandings and opinions on those SDC fundamentals: what is a component? how to use it? how to chose between slots and props? and other topics...

    I know Experience Builder is trying to build both a display builder (a better Layout Builder) and an UI components loader/manager (like UI Patterns 2), and I understand it is not an easy task. But I am also afraid the components management may be bent in some ways we may regret later, in order to comply with the current state and needs of the display builder.

  • Assigned to lauriii
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    I hope it will be useful and appreciated by the SDC community.

    I think that belongs in Drupal core! (Although I could see that the performance cost might be too high ๐Ÿ˜ฌ)

    Do you have an example [โ€ฆ]

    No, not yet. ๐Ÿ˜ญ This is something I've been asking @lauriii to clarify and formally document in ๐Ÿ“Œ Clarify "components" vs "elements" vs "patterns" Active .

    [โ€ฆ] but I am also surprised [โ€ฆ] But I am also afraid the components management may be bent in some ways we may regret later, in order to comply with the current state and needs of the display builder.

    Great concerns. I very strongly agree.

    Two observations:

    1. I don't know what those different perspectives are. ๐Ÿ“Œ Document supported component modeling approaches Active (another issue needing formal documentationโ€ฆ) is the closest we have to answering what "our perspective" is. You'll see that I'm not leading that conversation, because I know that I'm not an expert. It's @lauriii and @ctrlADel who've been the voices in that issue. I think it'd be great for you to participate in that issue's discussion ๐Ÿ™
    2. The current SDC-based implementation is just an early implementation, in service of ๐ŸŒฑ Milestone 0.1.0: Experience Builder Demo Active . After that's done (after DrupalCon Barcelona), attention will shift towards generalizing, i.e. supporting more "component types": ๐ŸŒฑ [META] Support component types other than SDC Needs work . IOW: the XB codebase will evolve.

    (FYI: the ADR + docs that were added last week in ๐Ÿ“Œ Document the current JSON-based data model, and describe in an ADR Active finally formally document what the status quo is and describes the need minimum evolutions we'll need to meet all XB product requirements.)

  • ๐Ÿ‡บ๐Ÿ‡ธUnited States Kristen Pol Santa Cruz, CA, USA

    This was very educational!

    For example, I didn't realize that attributes were injected as I saw them explicitly in XB components, e.g.

    https://git.drupalcode.org/project/experience_builder/-/blob/0.x/compone...

    Based on this, I'm assuming we can just remove them from our SDCs.

  • ๐Ÿ‡ซ๐Ÿ‡ทFrance pdureau Paris

    Indeed, I would not recommend to add this to your component definitions:

        attributes:
          type: Drupal\Core\Template\Attribute
          name: Attributes
          title: Attributes
    

    Because this prop is injected automatically by SDC anyway.

    But most importantly, because using a PHP namespace as a prop type is not JSON Schema compliant. It is an SDC quirk, a Drupalism, we need to get rid off.

    Related issue, kind of: โœจ HTML attributes as Twig mappings instead of PHP objects Active

  • ๐Ÿ‡บ๐Ÿ‡ธUnited States Kristen Pol Santa Cruz, CA, USA

    Thanks! Created followup for XB:

    ๐Ÿ“Œ Remove attributes in XB components Needs review

    and reopened ours for SDDS:

    ๐Ÿ“Œ Update SDDS SDCs attributes prop to align with XB Fixed

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    #11 + #12: wow, that means this is yet another thing that SDC in core should be doing differently/better. That pattern is literally all over Drupal core! ๐Ÿคช

    Responding in more detail over at ๐Ÿ“Œ Remove attributes in XB components Needs review โ€” let's continue that there.

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    @pdureau detailed response at #3470575-7: Remove `attributes` prop from all SDCs in the Experience Builder module โ†’ , looking forward to your feedback! ๐Ÿค“๐Ÿ™

  • ๐Ÿ‡ซ๐Ÿ‡ฎFinland lauriii Finland

    Elements are ultimately built-in building blocks provided by the Experience Builder. These will be eventually used by the component to build components that would be exposed within the component library.

    It seems that the confusion is likely arising from the fact that currently both elements, and components are defined using SDC and from that perspective they look alike. As argued by #5, there could be ways to define them outside of SDC but I'm not sure I understand why that would be required, so long as we can separate elements from components?

    Even if they are both defined as SDC, they are different from UX perspective, and elements would not be stored as part of a component library. Currently the UX designs are separating the elements from the component library for this reason.

    Many of the elements could be expressed as:
    <{{ html_tag }}{{attributes}}>{{ content }}</{{ html_tag }}>

    Even if we do that, we need to define the html tags / attributes available somewhere so that we can optimize the UX for the specific element. For example, it may not make sense to show the background color or font family options for an image whereas it makes sense for a container. Also, images need to have a field for alt text whereas other elements don't.

  • ๐Ÿ‡บ๐Ÿ‡ธUnited States ctrladel North Carolina, USA

    Images fall into the weird category of being both an element and a component. They should be individually placeable within slots or on a page but are also a fundamental building block of other components.

    it has a single prop, also called "image", so the component looks like a meaningless wrapper around this single prop

    I've found this to be a good way to future proof component definitions, it appears like a meaningless wrapper until there's a need to add another prop that is not directly an attribute of the image.

    it doesn't use the expected attributes object

    Attributes has always felt like an SDC antipattern that was included only to ease the integration with Drupal. This image use case is a great example of how a Drupal render array ends up having significant undefined impacts on the rendering of the component. An image component schema that fully defines/handles all the various ways to render an image as an html element would be way better then relying on whatever is in the attributes object but would be challenging with how much of an image's format/style is currently done in Drupal's render layer.

    This issue is also making me wonder if part of the scope of ๐ŸŒฑ [META] Support component types other than SDC Needs work should be allowing media(and other entities?) to be placed directly in XB using view modes.

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    This issue is also making me wonder if part of the scope of ๐ŸŒฑ [META] Support component types other than SDC Needs work should be allowing media(and other entities?) to be placed directly in XB using view modes.

    Interesting! ๐Ÿค” I'll think about that some moreโ€ฆ (this reminds me of the block_content block plugin, which I've been thinking about in the context of ๐Ÿ“Œ Add support for Blocks as Components Active .)

    Based on #15 and #16, I think this needs input from @pdureau.

    Attributes has always felt like an SDC antipattern that was included only to ease the integration with Drupal.
    [โ€ฆ]
    An image component schema that fully defines/handles all the various ways to render an image as an html element would be way better then relying on whatever is in the attributes object

    ๐Ÿ’ฏ โ€” it's where the SDC abstraction feels broken/wrong/in violation with itself.

Production build 0.71.5 2024