Problem/Motivation
The block listing in Layout Builder is a little overwhelming for users. When adding a block to a Standard profile Article, there are 59 block plugins in the list. You can imagine that with contrib enabled this list would become even longer and more irrelevant for the majority of users. It looks like this, currently:

Proposed resolution
By default close all categories except for the entity type categories which contain the field blocks.
Inside the entity type categories move all of the non view configurable fields, anything that doesn't show up on the "Manage Display" page of the Field UI module, into a subsection labeled "More",
Here is the listing when it is first opened

Clicking "More" will show the other fields for the entity type.

Remaining tasks
The following issues are not blockers, but they are related because they will do even more to make the UI simple and pleasing for users:
- #2968500: Change inline blocks workflow in Layout Builder to match mocks
- #2998862: The Layout Builder block listing should be filterable
Accessibility blockers for this issue
- #3037121: Disclosure triangle is missing in details/summary groups in off-canvas dialog in Firefox
- The bug in comments #120-121
User interface changes
Yes. See above.
API changes
None
Data model changes
None
| Comment | File | Size | Author |
|---|---|---|---|
| #139 | interdiff__133-139.txt | 12.42 KB | bnjmnm |
| #139 | 2977587-139.patch | 39.39 KB | bnjmnm |
| #137 | 2977587-137.patch | 34.45 KB | vadim.hirbu |
| #135 | 2977587-135.patch | 34.75 KB | kostyashupenko |
| #133 | 2977587-133.patch | 33.86 KB | bnjmnm |
Comments
Comment #2
bkosborneContrib has already started on this: Layout Builder Restrictions. I think it makes sense for core to provide this to avoid the jarring out of the box experience that currently exists with the overwhelming list. If core absorbed that work, it could provide a default set of blocks that are hidden/not shown while still allowing edge cases to use them if they want.
Comment #3
johnwebdev commentedFirst a +1
I think this definitely should be default behaviour, this is a great UX improvement and is especially great for the new Drupalisters when trying LB.
However, it's important that these can be re-added easily which is why I think a UI would probably be a good option to do this and ideally enabled by default.
If we're not keen to add a UI because reasons, the original definitions should be added to the hook so you can, again add them back easily.
Comment #4
tedbowI haven't looked at Layout Builder Restrictions yet but think core do a lot just promoted the entity fields where
$field_definition->isDisplayConfigurable('view')This patch does
Changes
FieldBlockDeriverto create 2 categories for each entity type 1 for'view'configurable field and one for those that aren't. For example for nodes it creates "Content" and "Content(extended)".Changes
ChooseBlockControllerto close all categories except Field Blocks for "view" configurable fields. Moves all field block categories to the top.This will produce something like this for nodes:

Comment #5
tedbowHere is try at that except using a nested
detailselement. Right it still looks like it on the same level as the other categories but think some CSS it would work.No doing an interdiff b/c these 2 approaches are pretty different.
So I created #2978939: Change 'field_block' block plugins to use "[entity_type] - fields" category to avoid confusion with other blocks
Comment #6
tedbowAdded test. While working on the test I realized there would a case where an entity type has only non 'view' configurable fields. This was the case for the test for the 'User' category. I think if you removed the "Picture" field after Standard profile install that would be the case.
🎉 for writing tests so we find this stuff out.
When this is the case it doesn't make sense create the "More+" section as there would be no other links in the category.
So functionality and test coverage is:
The reason a "entity" category could have no 'view' configurable fields but still have link directly under the category is because of #2978939: Change 'field_block' block plugins to use "[entity_type] - fields" category to avoid confusion with other blocks
Comment #7
tedbow🎉for actually uploading the files 😜
Comment #8
tedbowComment #9
tim.plunkettComment #10
tim.plunkettThis bit is stale, it's currently
Could this patch be made into a part of the filtering code? Or are there changes 100% needed in this markup?
Comment #11
tedbow1.
Not sure what you referring to the code that you mention with the call to
getFilteredDefinitions()is already in the patch about this.We still need to call
\Drupal\Component\Plugin\CategorizingPluginManagerInterface::getGroupedDefinitions()we need to call this to get the definitions in sorted groups with the labels also sort by definitions. Because we are sending the$definitionsit will use our filtered list.2.
I don't think we can do this in filtering. We aren't actually filtering out any plugins. Just nesting non view configurable fields(unless they are the only ones for entity)
Rerolled
Comment #12
savkaviktor16@gmail.com commentedComment #14
phenaproxima:(
Comment #15
phenaproximaComment #18
Anonymous (not verified) commentedThe #15 patch has been applied. It works. New test is passed successfully Drupal\Tests\layout_builder\FunctionalJavascript\LayoutBuilderUiTest . Few tests are failed because of new patch in another tests. The current test decoupled some logic to be reused in the current test. Should we create a base test class or trait to reuse it in another related tests? Tests are failed.
Comment #19
Anonymous (not verified) commentedThe tag has been added to make the issue visible on the Kanban sprint board.
Comment #20
mpotter commentedThis patch causes an error in 8.6-rc2:
when trying to add a new block. Looking at the code, this patch adds:
in the ChooseBlockController and the $field_block_category_weight is not defined anywhere.
Comment #21
tim.plunkettThat got lost in the reroll, it was in #11
Comment #22
Anonymous (not verified) commentedThe patch #2977587-11: Improve block listing in Layout Builder by hiding uncommon block plugins has been rerolled. There is differences between #2977587-15: Improve block listing in Layout Builder by hiding uncommon block plugins and #2977587-22: Improve block listing in Layout Builder by hiding uncommon block plugins. Could anybody answer to #2977587-18: Improve block listing in Layout Builder by hiding uncommon block plugins?
Comment #24
Anonymous (not verified) commentedComment #25
phenaproximaFixing invalid use statement in FieldBlockDeriver.php.
Comment #26
samuel.mortensonCan someone upload before/after screenshots or GIFs of the latest patch?
Comment #28
tedbowFixing tests that were failing and some that would fail now that #2978939: Change 'field_block' block plugins to use "[entity_type] - fields" category to avoid confusion with other blocks is in.
Created a base test because other tests will now need to click categories before adding some blocks.
i don't think we can use
:containsanymore because really we want an exact match on the category. FixingScreenshots


First opened
After clicking "More" under content fields.
Comment #30
tedbowWhoops left debug statement in.
Comment #31
phenaproximaNice! I found some stuff, but nothing serious. Overall I think this makes a lot of sense.
Why is $entity_type_label a reference?
I'm not sure how I feel about these variable names; I don't think they clearly communicate the intent. Maybe $main_field_block_links and $secondary_field_block_links would be better?
I feel like we should add the + using CSS, rather than stylizing the string here.
in_array() should have TRUE as a third argument.
Can we add a @see reference here?
Pro-tip: If find() cannot find the link, it will return NULL, which will cause a fatal if you try to call ->click() on it. A more preferable way to do this would be:
This will fail gracefully (i.e., an assertion, error message, proper cleanup) if the link does not exist.
The method is called assertBlockLinkVisible(), and the assertion is checking that the link is, in fact, visible. :)
Same idea here -- use assertSession() to be sure the element exists, then you can call isVisible() on it. Also, why use assertNotEmpty() here instead of assertTrue()?
Alternately, wouldn't $this->assertSession()->waitForElementVisible() work here?
Should be protected.
Pro-tip: You can do this in one line:
$assert_session->elementExists('named', ['link', 'Manage layout'])->click();Doc comment is wrong. Also, shouldn't this method be in LayoutBuilderTestBase?
Why not use assertFalse() here?
Should be ===
I wonder if assertSame() is more correct here.
If the details element is not found, ->find() will be called on null and the test will fatal. Maybe this should assert that the details is an instance of NodeElement before it calls ->find() on it?
Comment #32
tedbow@phenaproxima thanks for the detailed review! 🙇♂️
1. Because we are assigning a new value to it in the loop.
Actually this is kind of confusing I am just going to create a new array
$entity_field_categoriesbecause that is more accurate.And get rid of need for
$entity_type_labels2.
$linkswill be all block links except field blocks links for field blocks where the field is not view configurable not just field blocks links. So all other blocks links would be in there 2. This because loop with go through all categories.I change to
$secondary_field_block_linksand$block_links3. fixed
4. fixed
5. added
6. fixed, thanks for the tip
7. fixed
8. Changed to
$this->assertNotEmpty($this->assertSession()->waitForElementVisible('css', "#drupal-off-canvas a:contains('$link_text')"));Because
waitForElementVisiblewon't actually fail the test because it is not an assertion.9. fixed
10. I feel like doesn't read as easily so the test is not clear. Looking for "named" element? Leaving
11. Fix doc. Moved to LayoutBuilderTestBase
Also change to
$this->assertEmpty($this->assertSession()->waitForElementVisible('css', "#drupal-off-canvas a:contains('$link_text')"));to match the new logic in
assertBlockLinkVisible12. See 11 change
13. fixed
14. fixed
15. fixed
Sorry had to re-roll not interdiff
Comment #34
tedbowWhoops forgot to add a couple of files
Comment #35
phenaproximaThere's a stray 's' at the end of the @see line. :)
Comment #36
huzookaPatch tested, and plays really nice, I really like it.
Only some minors.
Remove '+' :)
I'd say that we don't need double quotations for the CSS selector here.
Prefer single quotations.
Prefer single quotation mark.
This is the only row where double quotation marks are used.
It's enough to check that
$summaryis not NULL, no need forinstanceof.if ($summary && $summary->getText() === $category)$this->findCategoryDetailswill return NodeElement or NULL. Why not useassertNotNullhere?Edit: after discussing with @phenaproxima, #6 and #7 MUST be ingored. The `instanceof` thing is good — it helps IDEs.
Comment #37
tedbow@huzooka thanks for the review, good catches.
1. Fixed
2. fixed
3. fixed
4. fixed
5. fixed
Also fixed #35
Comment #38
phenaproximaCode looks good to me, and @huzooka has confirmed the patch works. We're also using it in Lightning. I'd say this is good to go.
Comment #39
tim.plunkettSorry to knock back from RTBC, but I didn't get a chance to jump in here until now.
Could this loop be turned into a protected method that is passed $blocks and $build[$category] or similar, and move all of this out of the (already too big) build method?
I think it would go a long way to keeping the code readable.
Comment #40
tedbowRefactored
getCategoryBuild()And also refactored
isFieldCategory()to determine if a category is a field block category.Comment #41
tim.plunkettBeautiful
Comment #42
webchickThis one needs a re-roll since the test class name conflicts with the one from #2919795: Add visual hints that Layout Builder work is in tempstore and will not be lost, or take effect until saved.
The apparent "after" screenshot in #28 looks vastly improved... I guess one concern tho is there are two primary cases for Layout Builder, at least that I can think of off the top of my head. The first is you're customizing the way an entity type looks overall and/or how a specific entity will look (node/user), and these defaults seem to work great for that. But the second is when you're creating a landing page/marketing promo page/etc, in which case you mainly want to bring in usually Views or custom one-off blocks you've made for said page. Those options now get buried in it looks like nine (minimum; since this is just core) other possible collapsible headings to click on. (And they all have very "Drupally" names :\ I realize that's out of scope, tho.)
Could more info be provided on the design rationale here for the hide/show logic? When people have seen this used in the field, are the default options exposed here enough for the "80%" case, or do we need to do some more design work? (Not necessarily in this issue—this is a huge step forward already.)
Comment #43
tim.plunkettRerolled as both this issue and another recently committed issue add the LayoutBuilderUiTest class.
Switched from a base class to a trait.
As this no longer removes plugins like "Main Content Block", I think the IS should be updated.
Comment #45
tim.plunkettRenamed the name in the file, but not the name *of* the file. Whoops.
Comment #46
xjmI believe the UX and UI scalability impact of this qualifies it as major.
Comment #47
tedbow@webchick thanks for the feedback
This is a good point.
there are a couple of related issues that will make this situation better though.
Will add a "Create new Content" or "Create new block"(wording to be decided) at the top of the block list.
This will either take you directly to creating a custom block or to a list of custom block types, if you have more than 1
This will make the "custom one-off blocks " easier to find
This will give a text box to filter/search for blocks. So hopefully it won't matter as much that blocks are "hidden" inside categories. The blocks will become visible if they match the search.
If we imagine the site builders will set up a new content type for landing pages that won't actually contain addition fields, because they will use custom blocks, view, etc, then we could actually have the listing behave differently in the case that the entity using the Layout Builder has no view configurable fields.
Right now we expand out any category that contains view configurable fields. So for the case of a node in the Layout Builder that will mean the node itself, if the bundle has view configurable, and the user, because the standard profile has a picture field.
So that means that even for a landing page type with no View configurable fields on the bundle the User Fields category would still be expanded if the profile image was there.
We could change the behavior of this patch to only expand out only the X fields category for the current entity type. So when using the Layout Builder for a node only expand out Content Fields and only if there are view configurable fields.
This would mean that for a landing page content type(or other content entity) with no view configurable fields we would have no category to be expanded by default. In that case maybe it would make sense to expand out all categories. So when making a landing page everything would exposed by default.
Comment #48
xjmCan we add a before screenshot to the IS, and the latest after screenshots? I don't see the "before" on the issue at all.
The two issues in #47 could be listed in the "remaining tasks" section.
Thanks!
Comment #49
phenaproximaMarking for screenshots and reroll.
Comment #50
phenaproximaRerolled, and added some before/after screenshots to the IS.
Comment #51
phenaproximaAdding the two issues mentioned in #47 to the IS, and to the related issues.
Comment #52
phenaproximaThis is very clearly a usability concern, so tagging accordingly.
Comment #53
tim.plunkettFeels weird to use
statickeyword inline instead of a static class property. Any particular reason?Weird to check both the
is_view_configurableflag AND the ID (also how is that the ID, notfield_block:something:something:whatever?I'd think it should be completely determined by a flag on the definition, so others could opt-in if they chose.
Wow, super odd to do this comparison via t() (and
render()!?)Are we sure this works when things are translated?
This is a bit odd, no?
Comment #54
tedbow@xjm, @phenaproxima and @tim.plunkett thanks for pushing this issue forward.
Re #53
For the blocks that use derivers the ids don't change. I checked this other block type and all views block definitions the id is
views_blockI changed this to
_is_secondary_layout_builder_blockHow do document this? layout_builder.api.php?
in_arraywasn't matching.changed to
$entity_field_categories[] = (string) $this->t('@entity fields', ['@entity' => $entity_type_label]);Which will get the translated string.
$field_definition->isDisplayConfigurable('view');to a variable firstComment #55
bendeguz.csirmaz commentedSince #2968500: Change inline blocks workflow in Layout Builder to match mocks patch #54 no longer applies.
Comment #56
bendeguz.csirmaz commentedMy attempt of a reroll.
Comment #58
bendeguz.csirmaz commentedFixed the tests.
Comment #59
bendeguz.csirmaz commentedComment #60
tedbow@bendeguz.csirmaz thanks for the re-roll
This logic the callable
$predicateseems overly complex to me.If seems if
getBlockLinks()just had argument$block_levelthat had 2 possible values, "primary" or "secondary" then you could get rid ofisPrimaryBlock()andisSecondaryBlock().And then possibly just call
getBlockLinks()directly and then you could get rid ofgetPrimaryBlockLinks()andgetSecondaryBlockLinks().At the very least
$predicateshould not be an optional parameter. We are only calling it twice. But would be in favor of just using something like$block_level.Comment #61
bendeguz.csirmaz commentedYes, I agree it's somewhat complex (I was thinking of creating a new class for this).
The point of making that parameter optional was that this function is called in existing code.
So if we go with the flag approach, we need at least 3 flags ("unfiltered", "primary" and "secondary").
I think a better approach is to just filter the blocks before passing them to the
getBlockLinksfunction.Comment #62
bendeguz.csirmaz commentedI was thinking something like this.
Comment #63
tedbowWhoops, I missed the third call with out the parameter.
Yeah I like the filtering before sending to
getBlockLinks()_is_secondary_layout_builder_blockI guess in layout_builder.api.phpComment #64
bnjmnmHere's a patch with styling for the "More" subsections. Visually it's not quite popping for me - There are additional changes I'd make if this styling was specific to Layout Builder. Since these styles are applied to the off-canvas in the Stable theme, I only made changes to nested
<details>so ensure it would not change the appearance of off-canvas content anywhere else on the site. Still accomplishes the necessary visual distinction.Screenshots provided showing open, closed with category-beneath open, and closed with category-beneath closed.
Comment #65
phenaproximaCan we rename this method to something more "active"? How about buildCategory()?
"moved to"
$is_secondary_block seems a bit superfluous. Once we've filtered the primary blocks, couldn't we just use array_diff_key() or something to get the secondary blocks?
Should the key maybe be more_blocks, rather than more_fields?
Comment #66
tedbowRe #64
I have te
I don't think we should make changes to "stable" them in this issue.
Can we keep the changes to layout Builder css with selectors to make sure it only effect our dialog callback.
Or if the current patch is functional then would just say don't include the css in this issue and open general issue for off-canvas css.
If the CSS changes are necessary for this issue then we should keep inside layout builder.
Comment #67
tedbowRemoving the "array api"
I talked with @tim.plunkett about his suggestion in #53.2
We agree that:
this is making an "array as API" which we don't want.
So this patch:
Review #65
@phenaproxima thanks for the review
Other changes
I realized we actually don't need the wait here because aren't waiting for ajax request. We are just clicking html details element which doesn't involve css.
This makes the test run a lot faster because
assertBlockLinkNotVisible()would always take the full wait time before.I removed this from trait because is less generic after removing the wait when you might want to check if a block link is visible and that would include a wait for the list to appear.
Now that the extra fields are in the "User Fields" category it will actually be open and moved to the top.
Changing the test to use an alter remove the extra fields from the list and then add them back. This will cause the "User fields" category to be closed and at the bottom and then open and at the top.
I started from #62 because of reason in #66 I didn't include @bnjmnm's patch in #65
Comment #69
tedbowTests failed because I removed
LayoutBuilderTestTraitbut I forgot thatAjaxBlockTestwas also using this trait.Looking at this again the method name or doc says nothing about waiting. I was just thinking because it had a wait it in before. With an assert on visibility no caller should assume it also has wait.
Comment #70
bnjmnmPleased to see that #66 recommends scoping the css changes to layout builder - this provides much more flexibility and I definitely prefer this styling to my prior iteration.
Change is CSS + adding some classes to make it easier to target.
Before
After
Comment #71
swentel commentedHmm, I guess I have one remark (actually it was from one of our clients). It's nice that groups don't need an additional request to the server, but 'Create custom block' does and has a different workflow. Just saying, don't want to block this at all :)
Comment #72
tedbow@swentel thanks for taking a look.
That is true but not related to this issue
That happened already in #2968500: Change inline blocks workflow in Layout Builder to match mocks
We could create a separate issue though to optimize that. We could already return the list of "Create [block type]"(if more than 1) and just not display it until the user clicked "Create custom block". So to the user the workflow would be the same just not another trip to the server.
But again that should be a different issue.
Comment #73
bendeguz.csirmaz commentedRerolled patch #70.
Comment #75
tim.plunkettThese are now
'/display/default/layout'Comment #76
bnjmnmopenAllBlockCategories()toLayoutBuilderTestTrait, which provides tests an easy way to un-hide the block list.assertWaitOnAjaxRequest()calls were failing. Replaced those withwaitForElementVisible, to look for something that would be returned on the Ajax request, and the tests passed.Comment #77
bnjmnmComment #78
sam152 commentedHow does this work when the primary way of authoring content for a layout is via inline blocks? In my case, content "Content fields" are actually just metadata which is almost always irrelevant to the content that ends up in the actual layout.
Comment #79
bnjmnmThe issues addressed in #76.3 were specific to my local environment, not the reroll.
Adding a new patch and diffs for #73 and #76
Comment #80
tedbow#78 @Sam152 "Create custom block"(which is what in code is called "inline-block" is still the top link. If you have 1 Custom Block type this is will take you directly add form if you have more than 1 it will take you to a list of block types.
As I mentioned in #72 we could open a different to optimize how many server calls this takes.
But this issue doesn't change that "inline blocks" are still promoted as way to make layouts.
Comment #81
sam152 commentedAh indeed. We have a large library of reusable custom blocks, so I believe those would also show up in a large list. I am currently experimenting with this sandbox for truncating large list of block plugins: https://www.drupal.org/sandbox/sam/3033243
Comment #82
geek-merlinComment #83
tim.plunkettThis is looking good! Just some nits.
Idk that we're splicing any more.
Might be personal preference, but it feels weird to have the array_filter callback split out to a local variable instead of inline. Usually to me that implies it is reused, but it is not here.
Use \Drupal\Component\Plugin\PluginBase::DERIVATIVE_SEPARATOR here instead of ':'.
I know LB does this wrong in other places, but let's stop propagating it further
You can use the ARRAY_FILTER_USE_KEY flag for array_filter and not have to do the array_keys or array_flip-ing, and that array_diff will be an array_diff_key
Comment #84
bendeguz.csirmaz commentedFixed #83.
Comment #86
bendeguz.csirmaz commentedI thought I was going to be smarter than Tim and use
array_diff_associnstead ofarray_diff_keyas suggested. It turns out array_diff can't deal with multidimensional arrays.Comment #87
bendeguz.csirmaz commentedComment #88
tim.plunkettAha, but if you want we have a DiffArray utility class that can handle that!
Comment #89
bendeguz.csirmaz commented#83.4 ARRAY_FILTER_USE_KEY was only added in PHP 5.6, so I'm reverting that part.
Comment #90
tim.plunkettAhhhh you're absolutely right. Thanks!
Comment #92
bnjmnmJust because I've run into this a few times recently: The two test errors look like they're happening because the blocks are not immediately available to click due to being collapsed inside a category. The easiest way to address is will probably be using
openAllBlockCategories();fromLayoutBuilderTestTraitto open all categories immediately after opening the "Add block" dialog.Comment #93
tedbowI think we should avoid
executeScript()if we can when writting JS tests. Since we are doing emulating what the user could do.I am changing this is actually click all closed categories to open them.
Comment #94
tedbowFYI I tried here to add
[aria-expanded="false"]to the CSS selector in the foreach but this does not work because after the first click it changes the xpath that NodeElement uses and then the click() won't work for other elements because they no longer exist at the exact xpath that Mink uses to keep track of the elements.Comment #95
bnjmnmI've done too much on this issue to RTBC it, but want to mention that the changes @tedbow made to the tests I wrote are definitely improvements. The end result is essentially the same, but it now accomplishes it by reproducing what a user would do so -- that == a better test.
Comment #96
bnjmnmConfirmed its OK for me to RTBC since the none of the changes since the last one came from me.
Comment #97
xjmDoes #3034347: Update the Layout Builder UI classes to implement BEM naming conventions affect the CSS here at all (i.e. are we still using the correct class names, and do any added class names also follow the standard)?
Comment #98
bnjmnmReroll
Comment #99
bnjmnmReroll passed - back to RTBC
Re: #97, no selectors in this ticket are impacted by the changes in #3034347: Update the Layout Builder UI classes to implement BEM naming conventions . This reroll just accounts for new line positions.
Comment #100
xjmBut the new selectors also don't appear to be following BEM.
Comment #101
johnwebdev commentedThe CSS included in this patch is definitely not BEM, I agree with @xjm.
Comment #102
bnjmnmSetting to NW to review CSS
Comment #103
xjmComment #104
bnjmnmRefactored CSS for BEM and added a few classes to
ChooseBlockControllerto facilitate that.Comment #105
phenaproximaThe CSS looks good to me, and if this passes tests, I'd feel fine re-RTBCing this once Lauri signs off.
Comment #106
lauriiiThe hover styles are very subtle. Has this been run past the accessibility team?
Nesting elements like this isn't supported by BEM (see official documentation). I suggest that we add new block element class called
layout-builder-secondary-blocksand this will then becomelayout-builder-secondary-blocks__summary.Comment #107
bnjmnm#106.1 -- Hover styling has been changed to use the default approach for details elements in off-canvas, where the background color changes instead of the text color. There are still some visual differences to distinguish primary from secondary, so tagging this with Needs Accessibility Review to get confirmation the approach is OK particularly since the default state has a bg color that matches the container.
#106.2 -- Changed the selectors so there isn't nesting
Comment #108
bnjmnmComment #109
lauriiiComment #110
tim.plunkettComment #111
tim.plunkettThe IS mentions removing blocks like "Help" and "Main page content".
That was the initial scope of this issue.
This issue has a very separate and complex solution now, but one that does not address the problem as originally defined.
Comment #112
tedbowUpdate issue summary
Comment #113
tedbowUpdated screenshots
Comment #114
tedbowMIslabeled screenshots
Comment #115
tim.plunkettThe "before" screenshot is stale (missing the filter textfield and the "create custom block" part)
Retitling as we're no longer removing anything.
Comment #116
phenaproximaAdding a new "before" screenshot to the IS.
Comment #117
andrewmacpherson commentedBe aware that details/summary in the off-canvas dialog is currently broken. If you're going to have details closed by default, then #3037121: Disclosure triangle is missing in details/summary groups in off-canvas dialog in Firefox is a must-fix.
Comment #118
andrewmacpherson commented"More" summary needs to be disambiguated.
Recommend calling these "More user fields", etc
Comment #119
andrewmacpherson commentedRe. #107
I don't understand what this means. What's the purpose of primary/secondary here? (i.e. the semantic difference between them)
If the difference is important, it must not be conveyed by colour alone, per WCAG "Use of Color" (level A),
Comment #120
lauriii. I'm not sure what is causing this, but for some reason, this patch removes most of the block groups from tab order on Chrome:

Comment #121
andrewmacpherson commentedRe. #120 - I replicated the problem. Firefox is affected too.
The image in 120 doesn't really help. You used the Focus Order Favlet, which doesn't pick up on all tabbable elements. Specifically it doesn't pick up the summary element.
The patch here isn't the problem, I can replicate it without using the changes here. What I found was that details/summary groups which are initially closed are kept out of the tabbing order in the off-canvas dialog.
The tiny patch attached here demonstrates this. The only change is it makes all details elements closed by default in ChooseBlockController. Try to replicate these steps:
I replicated the same behaviour with Chrome72 and Firefox65 (on Kubuntu Linux 18.10 fwiw).
Note: Views UI has some details groups which are initially closed, in the floating dialog type. These don't seem to be affected. So maybe something is different about the way off-canvas dialog constrains tabbing?
That's all I got so far. It looks like this patch has uncovered a pre-existing bug.
Comment #122
andrewmacpherson commentedAdding accessibility blockers to the issue summary:
Comment #123
bnjmnmChanges made:
@todoreferencing #3037121: Disclosure triangle is missing in details/summary groups in off-canvas dialog in Firefox.font-weight: normal;rule to the secondary category summary so there is more-than-color visual distinction between it and the primary category details element is is nested incollapse.jsdetails polyfill. Accompanied by a@todoreferencing #1839158: Replace collapse.js with a proper polyfill for <details>. A png was also added that overrides the default (poor contrast) image used by the polyfill. Before and after screenshots are attachedjs-layout-builder-categoriesso it matched the naming of the nonjs-prefixed class it is accompanied by.@todoto an issue I created #3038336: When jQuery UI constrains tabbing it does not consider summary elements@todosto remove those fixes when the broader issue is addressed.Comment #125
andrewmacpherson commentedRestoring the a11y blockers to the summary - please leave them in place, even if you have attempted to fix them. There's an important difference between "accessibility issues have been identified, then fixed" and "accessibility issues have been identified, then lost".
Comment #126
andrewmacpherson commented#123.2 - I still don't know what primary and secondary refer to here. Can someone answer my question from #119?
Comment #127
bnjmnmPrimary and secondary categories are referring to the

<details>elements in the block listing. Secondary categories are nested inside primary categories.Comment #128
andrewmacpherson commented#127 - thanks, but how does that relate to #107? What was the part you wanted accessibility review for? Something to do with background colours?
Comment #129
andrewmacpherson commented#123 - parts 1 and 3: I don't think it's a good idea to fix things here, just for the sake of this feature request.
#123.1:
I can't find this @todo - the string "3037121" doesn't appear in patch #123. What is the fix that you used? Does it addrees the bug for all details groups inside an off-canvas dialog?
#123.3:
The collapse.js polyfill is a red herring here; it doesn't attempt to provide a disclosure triangle icon. The icon comes from the Classy theme.
Is there any reason why this can't use
#drupal-off-canvas .collapse-processed > summary:before {}, and live insidecore/misc/dialog/off-canvas.details.css? The selector it is overriding is.collapse-processed > summary:before {}, which isn't layout-builder specific. As it stands, this code only attempts to fix the appearance issue for a specific form controller. That's a great disservice to developers of contrib and custom modules, who have a reasonable expectation of being able to use the same elements as layout builder does. It's at odds with our principle of making software that anyone can use.I still think #3037121: Disclosure triangle is missing in details/summary groups in off-canvas dialog in Firefox should be a blocker for this issue.
Comment #130
andrewmacpherson commented#123.5:
Did this get cross-browser manual testing? In IE and Edge, the summary element isn't the operable control. We must not add
tabindex="0"to an element that isn't operable. I'm concerned that this will double the number of tab-stops, but only half of them will actually do anything.Update: I tested patch #123 in IE11 + Edge 42, on Windows 10. The double tab-stop problem does indeed happen. For sighted keyboard users, it's effectively a control which only works half the time. The workaround (carefully count the tab stops) would be hard to discover IMO. We can't use this approach.
Comment #131
tim.plunkett@andrewmacpherson it is common to provide temporary solutions that workaround known core bugs which would be out-of-scope to fix in this issue.
The above @todo is sufficient for this issue.
Comment #132
andrewmacpherson commentedPer #130,
tabindex="0"is not a viable fix. It makes things worse in 2 browsers that aren't affected in the first place.Comment #133
bnjmnm#126
Thanks Andrew! In this case, if you have the chance, could you just test the patch as-is and see if there are any specific problems that stand out in general? That's probably what will help the most at this point.
#129
The scope of this issue is Layout Builder. An issue already exists (however neglected it might be) to replace
collapse.js#1839158: Replace collapse.js with a proper polyfill for <details>. The CSS in classy that adds the triangle includes the class.collapse-processed, a class that is only present on elements modified by collapse.js.I'm very glad you caught that. This helped me narrow it down to a jQuery UI bug. There is a Drupal-wide fix in #3038336: When jQuery UI constrains tabbing it does not consider summary elements that is currently awaiting review. A Layout-Builder specific version with a @todo was also added - a precaution in case there are obstacles in getting 3038336 committed.
Comment #134
tim.plunkettComment #135
kostyashupenkoIt's just a reroll.
needs review
Comment #137
vadim.hirbu commentedTried to reroll the latest working patch #133.
Can't recreate interdiff file.
Comment #139
bnjmnmRerolled #133 and the interdiff is based on that. Some additional changes:
ChooseBlockControllerComment #140
saltednutI am cruising through this one (sorry) and I don't want to discount the work and decision making here but I do feel like adding the "more" subsection to every category is just really confusing and... sadly... oh so very Drupaly of us.
My opinion coming: A simple and elegant solution here is really to just dial it back.
1. Change 'TRUE' to 'FALSE' on line 162 of
ChooseBlockController2. Optionally: Add some JS that uses local storage to remember which categories were last open.
3. Optional, but important: Use layout_builder_restrictions and safe-list only the blocks useful to your clients. (see: #2998848)
I am adding a patch here that does the true/false swap and I'll go ahead and 'DO-NOT-TEST' the title to let y'all do what you want to do on this.
I know I am coming in with a bomb here and you have every right to ignore it.
For Acquia's Demo Framework, unless I see something better than what's currently proposed, I'm just going to do #1 and #3 mentioned above, because its simple and I don't really understand what you all are trying to do here with these psuedo-category "More" bump out subsections.
It's making me think and I don't believe that's what we want users to have to do here?
Comment #141
rlnorthcuttJust wanted to add the other issue that has this patch. Seems like a nice fix.
https://www.drupal.org/project/drupal/issues/3069446
Comment #142
webchickJust confirming that this came up in a recent UX test that Acquia did of Layout Builder, reaffirming the "major" status here. The block listing was overwhelming to users and they were unable to use it to find what they were looking for.
Comment #143
saltednut> The block listing was overwhelming to users and they were unable to use it to find what they were looking for.
Have we determined then that the best solution is to hide some blocks while making others available via the extra "More" fieldset? You've just described a problem but the issue still is proposed in the form of a solution. Its right in the title, "by hiding uncommon block plugins"
I don't disagree that hiding some things is a possible solution, but its weird to me that this was worked on for so long without anyone really questioning the UX decision proposed initially.
Comment #144
webchickNo, that's totally fair. It might be worth splitting out a separate issue to talk about solving the "OMG SO MANY THINGS" problem separately, and see if something like this or #3069446: Layout builder's "Add Block" sidebar menu UX improvements or something else entirely is the best way to handle that.
Comment #145
webchickDid that: #3073648: The list of available blocks in Layout Builder is overwhelming to users
Let's postpone this issue on a more holistic discussion of how to tackle this.
Comment #149
mvdve commentedFor the people looking for a solution: The Block list override module does a good job in cleaning up the layout builder list.