Overview
XB was originally developed with support SDCs, exclusively.
Then in November 2024, we added support for block plugins (in #3475584: Add support for Blocks as Components) and introduced the
concept.ComponentSource plugin
The problem:
ComponentSourceInterfaceand surrounding infrastructure was built (and evolved) on an as-needed basis, not always with an eye towards making this a public API- hence test coverage is partial at best
- there have been many
ComponentSource-specific bugs for aspects/edge cases other component source plugins already fixed - combined, this means it's hard to be confident about the production-readiness: robustness, edge case handling, etc.
We know there's both known technical debt, and more features that we'll eventually need to support:
- debt: the explicit input schema must be able to evolve, and each
ComponentSourcemay have different needs for that. For example: block plugins may change their settings (and their config schema), SDCs may gain new optional inputs, JS components may gain new required inputs - debt: we know we'll need to support implicit inputs (e.g. block plugins can declare required + optional "contexts" that allow block plugins behave differently not only to component instance author's explicit wishes ("explicit inputs"), but also based on the component developer's logic ("implicit inputs")
- feature: asymmetric translation will need some explicit inputs to be locked, because some explicit inputs may be considered to be not translatable — for example an image input of some component
Note: All ComponentSources targeted for XB 1.0-beta1 (#3515932: Milestone 1.0.0-beta1: Enable creation of non-throwaway sites):
sdc→\Drupal\experience_builder\Plugin\ExperienceBuilder\ComponentSource\SingleDirectoryComponentblock→\Drupal\experience_builder\Plugin\ExperienceBuilder\ComponentSource\BlockComponentjs→\Drupal\experience_builder\Plugin\ExperienceBuilder\ComponentSource\JsComponent_name tbd_→ stabilizing this highly experimental component source is out of scope for this meta, that has its own issue: #3519737: ADR for dynamic code components
Beta blockers (July 2025)
Beta blockers (tag: beta blocker) MUST happen before #3515932: Milestone 1.0.0-beta1: Enable creation of non-throwaway sites.
(Numbered lists must happen one after the other, bulleted lists can happen in parallel.)
- ✅ Test coverage to gain baseline confidence, and establish equivalent test coverage for all component sources, powered by a new
ComponentSourceTestBase:- ✅ #3501290: Introduce unit test coverage for both ComponentSource plugins (Block + SDC)
-
- ✅ #3518835: Move components/sdc_statuses/* SDCs into `xb_test_sdc` module
- ✅ #3518838: ComponentSource robustness: add `ComponentSourceTestBase::testSettings()`
- ✅ #3518833: [PP-2] Update JsComponentTest to subclass ComponentSourceTestBase for consistent test coverage
- ✅ #3518832: ComponentSource robustness: add `ComponentSourceTestBase::testGetClientSideInfo()`
- Incomplete functionality (due to demo-driven development) — which must ALWAYS expand a
ComponentSourceTestBase-powered test:- ✅ Discovery of components in a source, and only allowing the ones we know will work reliably:
- ✅
block: #3520617: BlockComponent::checkRequirements() should disallow any block plugins whose definition declares it requires certain contexts - ✅
sdc,js: #3508725: ComponentMetadataRequirementsChecker::check() should validate that the example(s) actually match the JSON schema - ✅ ALL sources: #3519168: Handle components provided by ComponentSources EXPLICITLY disappearing — enables deleting JS components that are in use
- ✅
block: #3484682: Handle update and delete of Block `Component`s, plus react to dependency removal - ✅
sdc: #3522164: Handle update and delete of SingleDirectoryComponent `Component`s, plus missing config dependencies - ✅
sdc#3523625: ComponentMetadataRequirementsChecker::check() should validate no prop is of `type: object` without a proper `$ref` - ✅
sdc,js: #3503087: Disallow SDCs with `type: string, enum: …` with an empty string listed to convey optionality: the prop should then just be optional
- ✅
- Correct rendering of components in a source:
- ✅
js: #3521072: Auto-saved Javascript Components CSS changes do not work with CSS aggregation - ✅
sdc,js: #3522673: Previews of SDCs with default image props broken - ✅
js: #3508937: Global AssetLibrary should render with its auto-saved state (if any) when rendered in the XB UI - ✅
block: #3518722: Test coverage to prove that BlockPluginInterface cacheability is correct when rendered via XB - ✅
js: #3522217: JsComponent-sourced rendered component instances lack cacheability of underlying config entities (+ first-party imports + auto-save tag when previewing) - ✅ ALL sources: #3521128: Ensure XB works with CSS + JS aggregation, including for (auto-saved) code components
- ✅
sdc: #3499352: SDCs should only have get HTML comments injected when `renderComponent(isPreview: TRUE)` - ✅
js: #3525374: Include compiled CSS from global asset library when displaying component library preview thumbnails - ✅
sdc: #3526967: Disabled SDC components are re-enabled after cache rebuild block: #3502371: Make "Page title block" work A) also outside regions, B) on the only routes XB currently supports: content entity routes
- ✅
- 🟢 Source's explicit inputs:
- ✅ Other
- ✅ ALL sources: #3502982: Rename ComponentSource settings' `plugin_id` to `local_source_id` or similar to not bias towards source plugins that don't use plugins under the hood
- ✅
js: #3521843: JS component slots and props don't appear in the preview canvas until published - ✅
js: #3516390: Compile Tailwind CSS globally for code components
Stable
ComponentSourceplugin API blockers (date: TBD)Stable blockers (tag:
stable blocker) do not block #3515932: Milestone 1.0.0-beta1: Enable creation of non-throwaway sites, but would be nice-to-have at that point in time.They MUST happen before #3517885: Milestone 1.0.0: Production Sites.This is for after #3517885: Milestone 1.0.0: Production Sites.To prevent contrib disruption prior to this being done: #3546903: Disallow using any ComponentSource other than SDC/JS/Block unless `canvas_dev_mode` is installed.
- ✅
sdc,js: #3544756: ComponentInstanceForm displays default value in the component form when value is empty. sdc,js: #3532414: Follow-up for #3500386: tighten `::collapse()` to improve data integrity, because new props added to auto-saved code components cannot have a widget anyway- #3526045: Settle on final name for `ComponentSource` plugins (`ComponentType`?) + expand their scope (discovery, maybe more?)
sdc,js: #3503038: Enable candidate `DynamicPropSource` suggestions for code components: refactor `GeneratedFieldExplicitInputUxComponentSourceBase` and `FieldForComponentSuggester` to need only SDC's ComponentMetadata, not SDC plugin instances, which will unblockjs: #3526520: JavascriptComponentStorage::createOrUpdateComponentEntity should not create component entities during config syncsdc,js: #3513562: Update StaticPropSource method names to reflect their stability Assigned to: meghasharma- ALL sources: #3492358: Provide ComponentSource-appropriate and -specific APIs to allow component instances to behave differently while being previewed
- ✅ ALL sources: #3523496: Block component instance form values not processed by validation/submit handlers
- ✅
block: #3518325: [11.2-only] BlockComponent::checkRequirements() requires block settings to be fully validatable, but XB pretended for demo purposes Views blocks are … now: error! 🛑 core blockers: - 🪦
block: #3484669: Define how block settings should be presented in the UI - 🪦
block: #3509265: Auto-saving of blocks needs to handle string-to-bool fixing block: #3526118: CSS assuming block-plugin-rendered-in-a-wrapper-for-the-block-config-entity does not apply to XB: either A) stay the course, B) simulate the same markup structure Assigned to: lauriiiblock: #3518656: Add Dynamic Page Cache and BigPipe support: `block` ComponentSource does not use placeholders/#lazy_builderblock: #3500795: [PP-1] Implement client-side validation of block settings- ✅ ALL sources: #3473761: Render a placeholder DIV inside empty Regions/Slots in the preview
- ALL sources: #3518250: [PP-1] Handle components instances rendering nothing: wrap them in a container
- Implicit inputs: make
BlockComponentsupport block plugins' required and optional contexts - #3513590: `ComponentSourceInterface::inputToClientModel()` needs to support passing a host entity
sdc,js: #3492366: Display SDC prop `description` as the form element description in component instances formblock: #3497990: [later phase] Support Block's PreviewAwarePluginInterface (and similar for other component sources)sdc: #3470422: Handle components provided by ComponentSources IMPLICITLY disappearing: gracefulness when developing SDCs: SDCs may appear/disappear from one request to the nextsdc: #3546208: [Needs design] Updating the `group` key in SDC's *.component.yml does not update it in Canvas editor (even after cache clear) Assigned to: lauriiisdc: #3546209: Support `replaces`: 2 SDCs with one replacing the other — Canvas creates `Component`s for both- Explicit input schema change strategies:: now has its own meta: #3524751: [later phase] Component Source plugins: generalized support for schema changes of explicit inputs.
- ALL sources: #3525691: Rename ComponentSourceInterface's singular method names to plural
block: #3524399: `BlockComponent::validateComponentInput()` allows garbage to pile up- ✅
sdc,js: #3524401: `GeneratedFieldExplicitInputUxComponentSourceBase::validateComponentInput()` allows garbage to pile up block: #3504925: Preview is not accurate for the site branding block: missing Olivero's CSS variablessdc: #3532514: Gracefully handle components in active development: ensure great DXjs: #3540082: JavaScriptComponent::getComponentUrl() gets calculated twice on render for each componentblock: #3541125: Integer BlockComponent inputs (i.e. block settings) are incorrectly saved as stringsblock: #3549793: ComponentInstanceForm fails to load for block components without any configblock: #3502376: Adding an empty block breaks annotation renderingblock: #3542194: 500 error when using Test Block Components- ✅
block: #3542102: Prevent publishing when `block` component instance values do not #validate sdc,js: #3565718: Validate `GeneratedFieldExplicitInputUxComponentSourceBase`-powered Component config entity props' `required` value matches the actual source for the `active` versionsdc,js: #3565755: Changing a slot's metadata (title/examples) should not generate a new Component config entity version- ✅
sdc,js: #3550882: Empty (optional) date prop throws error upon reload, due to bug in client-side transform sdc,js: #3530808: Example values for SDC props powered by datetime fields (in core, more in contrib) are not config schema-conformant because Canvas does not call `FieldItemListInterface::processDefaultValue()` Assigned to: wim leersblock: #3572850: "block" ComponentSource plugin should never store inputs for `label` and `label_display`, because they're not available for Canvas users Assigned to: lauriii- ✅
js: #3574120: Validate props for code components when rendering, like SDCs do sdc,js: #3576578: Inform SDC/code component developers of nonsensical `type: array` prop restrictions: `maxItems <2`- #3576805: DX: reorganize test components: `canvas_test_sdc` should have its (intentionally invalid) SDCs moved to `canvas_test_sdc_invalid` Assigned to: wim leers
block: #3578142: [upstream] New Views blocks are not available to be placed until cache clearblock: #3558721: Regression: can no longer access previously stored values for block component instances
Post-stable priorities (after achieving a stable PHP API)
Post-stable priorities (tag:
post-stable priority) do not block any release, and are things we'd like to see happen, but are intentionally NOT happening any time soon. We're highly confident that these will be net additions without the need for backwards compatibility breaks. - ✅ Discovery of components in a source, and only allowing the ones we know will work reliably:
Comments
Comment #2
wim leersComment #3
wim leersComment #4
wim leersComment #5
wim leersComment #6
wim leersComment #7
wim leersComment #8
wim leersComment #9
wim leersComment #10
wim leersComment #11
wim leersComment #12
wim leersComment #13
wim leersComment #14
wim leersComment #15
wim leersComment #16
wim leersComment #17
wim leersComment #18
wim leersComment #19
wim leersComment #20
wim leersComment #21
wim leersComment #22
wim leersDiscussed
#explicit-input-schema-change-strategiesin detail with @longwave just now. Here are the meeting notes:However … it can't actually work because we won't know which of those post-update hooks are associated with which block plugins! In theory, we could run all those block-targeting post-update hooks, but then we'd need to track for every single block-sourced component instance which update hooks have already been executed (equivalent to how core does the system-wide
UpdateRegistry). That doesn't scale, just like it doesn't scale to update potentially millions of (revision) rows.ExplicitInputSchemaChangeStrategyEnumin the current IS) will be necessary. And there may be a need for even more. It really depends on how a particular component source functions. Future ones: layout types, paragraph types, web components, external API shenanigans, etc. — it's literally anything. So we cannot lock ourselves into one corner.Conclusion: both my ideas (articulated in this issue + #3520449) and @longwave's (at #3501708-9) have been invalidated 😅 But we both agree that #3457504: XB field type: calculate all dependencies, store them, surface in new Component "Audit" operation is an important step towards more clarity on how we might solve this.
Comment #23
catchOpened #3521221: Block plugins need to be able to update their settings in multiple different storage implementations in relation to #22.
Comment #24
larowlanI think we're missing #3500795: [PP-1] Implement client-side validation of block settings in the scope here - at present we're relying on the 'jsonSchema' of SDC (and via the ephemeral SDC plugin in Code components) to show validation errors in the UI but we don't have another source component that has clientside validation so can't be sure the API is ready
Comment #25
wim leers#3518832: ComponentSource robustness: add `ComponentSourceTestBase::testGetClientSideInfo()` and #3521072: Auto-saved Javascript Components CSS changes do not work with CSS aggregation landed 🚢
Comment #26
wim leersReplacing #3497990 with #3518250: [PP-1] Handle components instances rendering nothing: wrap them in a container per @lauriii at #3497990-18: [later phase] Support Block's PreviewAwarePluginInterface (and similar for other component sources).
Comment #27
wim leersAdded #3522217: JsComponent-sourced rendered component instances lack cacheability of underlying config entities (+ first-party imports + auto-save tag when previewing).
Comment #28
wim leers#3520617: BlockComponent::checkRequirements() should disallow any block plugins whose definition declares it requires certain contexts and #3502982: Rename ComponentSource settings' `plugin_id` to `local_source_id` or similar to not bias towards source plugins that don't use plugins under the hood landed.
Comment #29
wim leersAdded:
Comment #30
wim leersAdded #3521843: JS component slots and props don't appear in the preview canvas until published.
Comment #31
wim leersComment #32
wim leers#3522673: Previews of SDCs with default image props broken landed a while ago. #3508725: ComponentMetadataRequirementsChecker::check() should validate that the example(s) actually match the JSON schema landed just now.
#3520944: Make menu blocks (block.settings.system_menu_block:*) fully validatable landed in core.
Comment #33
longwave#3521843: JS component slots and props don't appear in the preview canvas until published was fixed in #3521819: Hovered preview for JS components in library not working anymore
Comment #34
wim leersAdded #3499352: SDCs should only have get HTML comments injected when `renderComponent(isPreview: TRUE)` and #3473761: Render a placeholder DIV inside empty Regions/Slots in the preview.
Comment #35
lauriiiComment #36
larowlanAdded #3523496: Block component instance form values not processed by validation/submit handlers
Comment #37
wim leersAdded #3513589: [upstream] Decouple GeneratedFieldExplicitInputUxComponentSourceBase from SDC plugins, #3500795: [PP-1] Implement client-side validation of block settings, #3523496: Block component instance form values not processed by validation/submit handlers.
Comment #38
penyaskitoAdded #3523625: ComponentMetadataRequirementsChecker::check() should validate no prop is of `type: object` without a proper `$ref`
Comment #39
wim leers#3508937: Global AssetLibrary should render with its auto-saved state (if any) when rendered in the XB UI and #3518722: Test coverage to prove that BlockPluginInterface cacheability is correct when rendered via XB landed.
Comment #40
wim leersNew category in the issue summary: . Prompted by the addition of #3521444: Required image field becomes non-functional after publishing with empty field.
Comment #41
wim leersAlso marked #3492358: Provide ComponentSource-appropriate and -specific APIs to allow component instances to behave differently while being previewed as less urgent.
Comment #42
wim leers#3523496 was in there twice 🙈
Comment #43
wim leers👉️🔄
Comment #44
wim leersComment #45
wim leersMoved #3503087: Disallow SDCs with `type: string, enum: …` with an empty string listed to convey optionality: the prop should then just be optional to "discovery" thanks to superb feedback from somebody in the community I've not seen before — wonderful way to start the day :)
Also: #3521128: Ensure XB works with CSS + JS aggregation, including for (auto-saved) code components landed!
Comment #46
wim leersLanded:
Added: #3525374: Include compiled CSS from global asset library when displaying component library preview thumbnails.
Comment #47
wim leersUpdated the issue summary to more clearly distinguish between:
Comment #48
wim leers#3525374: Include compiled CSS from global asset library when displaying component library preview thumbnails landed.
Removed #3460230: Component entity config dependencies are incomplete: missing ComponentSourceInterface::calculateSettingsDependencies() to compute deps for field storage + instance settings + widget, because that belongs in #3520449: [META] Production-ready data storage, where it is already being tracked.
Moved #3518250: [PP-1] Handle components instances rendering nothing: wrap them in a container and #3473761: Render a placeholder DIV inside empty Regions/Slots in the preview to stable blocker (but in order to understand whether that's appropriate, I actually … kinda ended up completely fixing that last one 😅)
Comment #49
wim leersTriaged the list of issues tagged . Added the following missing stable blockers:
And also one overlooked beta blocker: #3516602: SDC `enum` props should have human-readable labels: use `meta:enum`
Now that triaging is done, I realized/discovered that only 3 known beta blockers remain:
sdc,js: #3516602: SDC `enum` props should have human-readable labels: use `meta:enum`sdc#3523625: ComponentMetadataRequirementsChecker::check() should validate no prop is of `type: object` without a proper `$ref`sdc,js: #3503087: Disallow SDCs with `type: string, enum: …` with an empty string listed to convey optionality: the prop should then just be optional— AFAICT fixed by a larger infra issue, being confirmed.)sdc: #3522164: Handle update and delete of SingleDirectoryComponent `Component`s, plus missing config dependenciesComment #50
wim leersAdded #3525691: Rename ComponentSourceInterface's singular method names to plural as a stable blocker.
Comment #51
wim leers#3522164: Handle update and delete of SingleDirectoryComponent `Component`s, plus missing config dependencies was confirmed as a duplicate 👍
Comment #52
wim leersFix HTML.
Comment #53
wim leersSome crucial text was lost in the #47 reshuffle.
Comment #54
wim leers#3523625: ComponentMetadataRequirementsChecker::check() should validate no prop is of `type: object` without a proper `$ref` is in.
Comment #55
wim leersAdded #3514672: [Needs design] DX & authoring experience: support `default` in addition to `examples[0]`, enables updating a component input across all existing instances to a new section.
Comment #56
wim leersComment #57
wim leersAdded these stable blockers:
block: #3524399: `BlockComponent::validateComponentInput()` allows garbage to pile upsdc,js: #3524401: `GeneratedFieldExplicitInputUxComponentSourceBase::validateComponentInput()` allows garbage to pile upComment #58
larowlanAdded #3526520: JavascriptComponentStorage::createOrUpdateComponentEntity should not create component entities during config sync
Comment #59
wim leersAdded #3509265: Auto-saving of blocks needs to handle string-to-bool fixing.
Comment #60
wim leersAdded #3504925: Preview is not accurate for the site branding block: missing Olivero's CSS variables.
Comment #61
wim leers#3503087: Disallow SDCs with `type: string, enum: …` with an empty string listed to convey optionality: the prop should then just be optional is in!
Comment #62
wim leersAdded #3526967: Disabled SDC components are re-enabled after cache rebuild as a new beta blocker.
Comment #63
wim leers#3526967: Disabled SDC components are re-enabled after cache rebuild landed.
Down to one remaining beta blocker again: #3516602: SDC `enum` props should have human-readable labels: use `meta:enum`.
Comment #64
wim leersAdded @phenaproxima's #3526045: Settle on final name for `ComponentSource` plugins (`ComponentType`?) + expand their scope (discovery, maybe more?).
Comment #65
wim leersThe beta parts are 99% done 🥳 — the only remaining one is #3516602: SDC `enum` props should have human-readable labels: use `meta:enum`, which is in the final stages, and the "land upstream support for this" part is already complete: #3493070: SDC `enum` props should have translatable labels: use `meta:enum`. 😊
Comment #66
wim leersh3 → h2
Comment #67
wim leersMoved #3502371: Make "Page title block" work A) also outside regions, B) on the only routes XB currently supports: content entity routes here from #3521002: [META] Maintainable client-side data model + internal HTTP API.
Comment #68
wim leersNew stable blocker: #3526118: CSS assuming block-plugin-rendered-in-a-wrapper-for-the-block-config-entity does not apply to XB: either A) stay the course, B) simulate the same markup structure.
Comment #70
wim leersGiven #3526644-9: Make basic webform experience work with Drupal Canvas, I think we actually need something like the
all-propsSDC but for block plugins.I suspect we actually need to expand what
\Drupal\experience_builder\Plugin\ExperienceBuilder\ComponentSource\BlockComponent::checkRequirements()does, because block forms can use arbitrary render arrays, and those are definitely not guaranteed to just work in XB.So I think
BlockComponent::checkRequirements()would at minimum need to be expanded with calling::blockForm()and traversing it to see if only "known to be working"#types are present 😅It seems that in core only the following
#types are used:actionscheckboxcontainerdetailsentity_autocompletefieldsetselectsubmittextfieldSome of those likely will require some work in XB's AFAICT.
Crediting @bnjmnm for putting #3526644 on my radar!
Comment #71
wim leersTogether with @bnjmnm I articulated a proposal at #3500795-8: [PP-1] Implement client-side validation of block settings 😊
Comment #72
wim leersAdded #3532414: Follow-up for #3500386: tighten `::collapse()` to improve data integrity, because new props added to auto-saved code components cannot have a widget anyway as a stable blocker.
Comment #73
wim leers#3473761: Render a placeholder DIV inside empty Regions/Slots in the preview and #3518325: [11.2-only] BlockComponent::checkRequirements() requires block settings to be fully validatable, but XB pretended for demo purposes Views blocks are … now: error! landed!
Comment #74
wim leersAdded #3532514: Gracefully handle components in active development: ensure great DX.
Comment #75
wim leersAdded #3540082: JavaScriptComponent::getComponentUrl() gets calculated twice on render for each component.
Comment #76
wim leersℹ️ @lauriii (together with @effulgentsia and I) decided to descope a stable
ComponentSourceplugin API to after 1.0.It'll still be around for contrib to experiment, but we realistically won't have the time to actually make it a stable PHP API with a BC promise before DrupalCon Vienna.
Comment #77
wim leersComment #78
wim leers#76 has been reflected over at #3454519-52: [META] Support component types other than SDC, block, and code components too now.
Comment #79
wim leersComment #80
wim leersAdded
Comment #81
wim leersAdded #3546903: Disallow using any ComponentSource other than SDC/JS/Block unless `canvas_dev_mode` is installed, which already landed thanks to swift @lauriii approval!
Comment #82
wim leersNew: #3544756: ComponentInstanceForm displays default value in the component form when value is empty. — and landed overnight.
Comment #83
penyaskitoCreated #3549814: Component tree containing theme's SDCs triggers errors when the theme is not the default anymore, didn't add to issue summary listing.
Comment #84
wim leersAdded #3549793: ComponentInstanceForm fails to load for block components without any config.
Comment #85
wim leersAdded #3502376: Adding an empty block breaks annotation rendering and #3542194: 500 error when using Test Block Components.
Comment #86
wim leersAFAICT we've got our first example of a slot-only
ComponentSource: theLayoutsource, which will enable a Layout Builder-to-Canvas migration.Comment #87
wim leersAdded #3542102: Prevent publishing when `block` component instance values do not #validate.
Comment #88
wim leersNew:
Comment #89
wim leersNew: #3550882: Empty (optional) date prop throws error upon reload, due to bug in client-side transform, #3530808: Example values for SDC props powered by datetime fields (in core, more in contrib) are not config schema-conformant because Canvas does not call `FieldItemListInterface::processDefaultValue()`.
Comment #90
wim leers#3550882: Empty (optional) date prop throws error upon reload, due to bug in client-side transform and #3524401: `GeneratedFieldExplicitInputUxComponentSourceBase::validateComponentInput()` allows garbage to pile up landed!
Comment #91
wim leersAdded #3572850: "block" ComponentSource plugin should never store inputs for `label` and `label_display`, because they're not available for Canvas users.
Comment #92
wim leers#3574120: Validate props for code components when rendering, like SDCs do was created yesterday and landed today :)
Comment #93
wim leersNew: #3576578: Inform SDC/code component developers of nonsensical `type: array` prop restrictions: `maxItems <2` and #3576805: DX: reorganize test components: `canvas_test_sdc` should have its (intentionally invalid) SDCs moved to `canvas_test_sdc_invalid`.
Comment #94
wim leersNew: #3578142: [upstream] New Views blocks are not available to be placed until cache clear.
Comment #95
wim leersNew: #3558721: Regression: can no longer access previously stored values for block component instances.