You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[6.x] Parts-only card event, with Craft 5 card HTML handled by the Yii adapter - #20354
Counter-proposal to #20335, based on its branch so the diff shows only what changes. Both card renderers still build the same parts and fire one event, but core no longer carries $html.
elementCardHtml() ─┐ ┌─ elementCardPartsHtml(parts)
├─ elementCardParts() → ElementCardParts ─┤
elementCardData() ─┘ fires ElementCardPartsResolving └─ card data array
(element, context, parts — no html)
Yii adapter listener (only if EVENT_DEFINE_ELEMENT_CARD_HTML has handlers):
parts → HTML → Craft 5 handlers → changed? → split back into parts
ElementCardHtmlResolving is renamed to ElementCardPartsResolving, with no $html, so there's one way to change a card and listeners can't override each other's parts changes.
The Dom\HTMLDocument parser moves from ElementHtml to the legacy Cp helper. HTML that isn't a card keeps the original footer, which holds the field's hidden input.
Both renderers give listeners identical parts: the selection checkbox is added at render time rather than stored in actionsHtml, and withThumb means the same thing in both.
ElementCards.vue passes cardAttributes.class through to <craft-card>, so classes listeners add show up on Matrix, relation and index cards.
ElementCardParts is a plain, non-final class without Arrayable, and headerHtml is renamed to labelHtml.
Tradeoff: Craft 5 handlers' HTML is always parsed back into parts, including for elementCardHtml(), so a handler that wraps the card in another element ends up with the wrapper as the card's content.
Evidence
Before:cardAttributes: {class: ['card', 'listener-class']} → <craft-card class="">; listeners got actionsHtml with the checkbox from elementCardHtml() but not from elementCardData(); a non-card Craft 5 override dropped the field's hidden input. After: each of those cases is covered by a test that fails on [6.x] Fire ElementCardPartsResolving for every element card #20335's branch and passes here (ElementCards.test.ts, ElementHtmlTest, adapter CpElementCardHtmlTest). The ElementCards Storybook story is pixel-identical before and after.
…pter
ElementCardHtmlResolving is renamed to ElementCardPartsResolving and only
carries the card's parts. Both card renderers build the parts and fire the
event in one place, so listeners see the same parts everywhere.
The Yii adapter renders the parts for Craft 5 EVENT_DEFINE_ELEMENT_CARD_HTML
handlers and splits changed HTML back into parts, keeping the original footer
when the result isn't a card.
ElementCards.vue now passes server card classes through to <craft-card>.
Amp-Thread-ID: https://ampcode.com/threads/T-06e10032-984e-4027-9c79-c92ca17a25e3
Co-authored-by: Amp <amp@ampcode.com>
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
The HTML-to-parts conversion loses wrapper attributes and sibling markup from Craft 5 overrides, while the fallback can duplicate field inputs and submit the same element ID twice.
This PR makes element-card customization parts-only in core and moves Craft 5 HTML override handling into the Yii adapter, keeping customization shared across HTML and component-rendered cards.
Changes:
Renames the card event to ElementCardPartsResolving and unifies parts generation, thumbnail behavior, and selection-checkbox rendering.
Moves legacy HTML parsing into the Yii adapter and preserves the original footer for non-card overrides.
Passes server-provided classes to Vue cards and adds regression coverage.
A handler that wraps the card already includes its footer, so the original
footer is only restored when the override lacks it. Markup a handler adds
next to the card root now goes in the footer instead of being dropped.
Amp-Thread-ID: https://ampcode.com/threads/T-06e10032-984e-4027-9c79-c92ca17a25e3
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
The server’s element class causes quick-edit to target the non-focusable card host instead of its focusable list item, breaking focus restoration after the editor closes.
No open issues 🎉
1 previously missed issue
In code that hasn't changed since last review
Prevent quick-edit focus lookup from selecting non-focusable card host
Passing through the server’s element class makes quick-edit’s closest('.element') lookup select <craft-card> instead of its focusable list item. After double-clicking a selectable card’s body and closing the editor, focus restoration targets that non-focusable host and fails. Keep listener classes, but filter out the structural element class here so quick-edit still finds the list item.
Re: Copilot's follow-up review: agreed. Because the server's element class reached <craft-card>, quick-edit's closest('.element') found the card instead of its focusable <li>, so focus couldn't be restored after the editor closed. That was caused by this PR's class pass-through.
This PR is already merged, so the fix is on #20335 in 2f1ccc2. The element and error classes now stay only on the list item, which itemClass() already gives them. Other server classes still reach the card. The ElementCards test now checks that the card doesn't get element and that closest('.element') is the <li>. It fails without the fix.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Counter-proposal to #20335, based on its branch so the diff shows only what changes. Both card renderers still build the same parts and fire one event, but core no longer carries
$html.ElementCardHtmlResolvingis renamed toElementCardPartsResolving, with no$html, so there's one way to change a card and listeners can't override each other'spartschanges.Dom\HTMLDocumentparser moves fromElementHtmlto the legacyCphelper. HTML that isn't a card keeps the original footer, which holds the field's hidden input.actionsHtml, andwithThumbmeans the same thing in both.ElementCards.vuepassescardAttributes.classthrough to<craft-card>, so classes listeners add show up on Matrix, relation and index cards.ElementCardPartsis a plain, non-final class withoutArrayable, andheaderHtmlis renamed tolabelHtml.Tradeoff: Craft 5 handlers' HTML is always parsed back into parts, including for
elementCardHtml(), so a handler that wraps the card in another element ends up with the wrapper as the card's content.Evidence
cardAttributes: {class: ['card', 'listener-class']}→<craft-card class="">; listeners gotactionsHtmlwith the checkbox fromelementCardHtml()but not fromelementCardData(); a non-card Craft 5 override dropped the field's hidden input.After: each of those cases is covered by a test that fails on [6.x] Fire ElementCardPartsResolving for every element card #20335's branch and passes here (
ElementCards.test.ts,ElementHtmlTest, adapterCpElementCardHtmlTest). The ElementCards Storybook story is pixel-identical before and after.Related issues