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

Comments

Wim Leers created an issue. See original summary.

Wim Leers credited pdureau.

wim leers’s picture

Status: Active » Needs review

👋 @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?

wim leers’s picture

Title: [PP-1] Update XB's `image` SDC to comply with best practices, and document those best practices » Update XB's `image` SDC to comply with best practices, and document those best practices
pdureau’s picture

Thanks Wim for creating this issue and give us the opportunity to discuss about those subjects.

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.

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

  • it could be leveraged 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

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: one of the 2 layers, the image component or the image prop, is superfluous 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 UI components. 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;

wim leers’s picture

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 #3467959: SDC and code component props should be able to receive HTML, editable in formatted text fields+widgets — I bet you'll want to chime in on that issue too :)

wim leers’s picture

WRT definition of "elements" — see discussion at #3455036: Clarify "components" vs "elements" vs "patterns", there's no definitive answer yet.

pdureau’s picture

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 but 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 (still WIP but already useful). 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 carefully curated set of SDCs, tagged/categorized as "elements"? Maybe experience_builder:image is not a good example, 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.

wim leers’s picture

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 #3455036: Clarify "components" vs "elements" vs "patterns".

[…] 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. #3446083: Document supported component modeling approaches (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 #3454094: Milestone 0.1.0: Experience Builder Demo. After that's done (after DrupalCon Barcelona), attention will shift towards generalizing, i.e. supporting more "component types": #3454519: [META] Support component types other than SDC, block, and code components. IOW: the XB codebase will evolve.

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

kristen pol’s picture

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.

pdureau’s picture

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: #3457874: HTML attributes as Twig mappings instead of PHP objects

kristen pol’s picture

wim leers’s picture

#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 #3470575: Remove `attributes` prop from all SDCs in the Experience Builder module — let's continue that there.

wim leers’s picture

@pdureau detailed response at #3470575-7: Remove `attributes` prop from all SDCs in the Experience Builder module, looking forward to your feedback! 🤓🙏

lauriii’s picture

Assigned: lauriii » Unassigned
Issue summary: View changes
Issue tags: -Needs product manager review
StatusFileSize
new356.44 KB

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.

ctrladel’s picture

Version: » 0.x-dev

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 #3454519: [META] Support component types other than SDC, block, and code components should be allowing media(and other entities?) to be placed directly in XB using view modes.

wim leers’s picture

Status: Needs review » Postponed (maintainer needs more info)

This issue is also making me wonder if part of the scope of #3454519: [META] Support component types other than SDC, block, and code components 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 #3475584: Add support for Blocks as Components.)


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.

lauriii’s picture

Issue summary: View changes
StatusFileSize
new106.51 KB
new83.44 KB
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.

Sorry for the late reply here! We don't have this experience fully designed (yet) but this was discussed on a high level as part of the IA exercise. The plan is to allow exactly this; allow images to be defined as props of components and as elements that could be placed in slots.

Because of that, for media, like videos, files, and images, there are elements inside the "Elements" group:

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

The "Dynamic Components" group includes a section that would allow inserting content directly using the entity view modes:

Next step is to design what the UX of inserting these would look like. That will likely be in ~3-4 months from now. In the meanwhile, there's some work around the image attributes in #3494545: [later phase] SDC must be able to specify minimum dimensions for a prop receiving an image.

wim leers’s picture

Title: Update XB's `image` SDC to comply with best practices, and document those best practices » [later phase] Update XB's `image` SDC to comply with best practices, and document those best practices
Status: Postponed (maintainer needs more info) » Postponed

Thanks for following through so quickly on my ping this morning, @lauriii 🙏😊

wim leers’s picture

FYI: the tangentially related #3501902: Adding the Image component results in a state considered invalid landed, which makes XB leap ahead of SDC on one front: XB supports SDCS providing a default image.

Updated the meta #3462705 at #3462705-43: [META] Missing features in SDC needed for XB.

wim leers’s picture

Project: Experience Builder » Drupal Canvas
Version: 0.x-dev » 1.x-dev

Experience Builder has been renamed to Drupal Canvas in preparation for its beta release. You can now track issues on the new project page.

wim leers’s picture

Title: [later phase] Update XB's `image` SDC to comply with best practices, and document those best practices » Update XB's `image` SDC to comply with best practices, and document those best practices
Status: Postponed » Needs review
Related issues: +#3535453: Create an Image SDC that can be included by other SDCs
penyaskito’s picture

Aside of whatever we need because of #3352063: Allow schema references in Single Directory Component prop schemas:

  • attributes is being used properly in the twig template of the image component.
  • Usage/ best practices of the image component is documented in Canvas SDC image docs.

So yes, feeling like this can be closed now.

wim leers’s picture

Assigned: Unassigned » lauriii
Status: Needs review » Reviewed & tested by the community

Marking RTBC — @lauriii also is an SDC expert, so let's have him have the final say.

lauriii’s picture

Assigned: lauriii » Unassigned
Status: Reviewed & tested by the community » Fixed

This has been completed from my perspective – the image component looks good. There might be a follow-up discussion to be had on best practices regarding the use of attributes object.

Now that this issue is closed, please review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, please credit people who helped resolve this issue.

wim leers’s picture

Great, thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.