Problem/Motivation
The navigation admin UI is tied to Layout Builder by design #3438895-24: Add the new Navigation to core as an Experimental module to reduce code duplication. Now that Layout Builder is not the future of laying things out in core, we need to prepare for it's removal. First step is to update the UI, another issue will need to deal with the new config format of the navigation configuration.
Steps to reproduce
Proposed resolution
Remove the dependency on the Layout Builder interface and create a bespoke UI that still generates Layout Builder configuration.
Remaining tasks
Define if there is an updated UI or if we simply replace the implementation while keeping most of the existing UX.
User interface changes
Updated interface for navigation sidebar configuration
Introduced terminology
API changes
none
Data model changes
none
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #14 | Screen Recording 2026-05-21 at 20.52.40.mov | 5.22 MB | gábor hojtsy |
| #14 | Screenshot 2026-05-21 at 20.55.09.png | 605.31 KB | gábor hojtsy |
| #12 | Screen Recording 2026-05-21 at 17.13.10.mov | 28.66 MB | gábor hojtsy |
Issue fork drupal-3521155
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
- 3521155-remove-layout-builder
changes, plain diff MR !15840
Comments
Comment #2
catchIt seems likely that this won't be the last blocker to deprecating layout builder, so I think it would make sense to remove the layout builder UI dependency as a by-product of the UX improvements, and then only have to do the implementation once (or at least, not definitely have to do it twice).
We briefly discussed that https://github.com/SortableJS/Sortable might be a good fit here - this only needs 1d drag and drop, and doesn't need/want a table so better to avoid tabledrag if we can I think. Sortable is already in core.libraries.yml so no new dependency.
Comment #3
ckrinaHuge +1 to this. As discussed with Navigation maintainers and several core committers the existing UI doesn’t meet the UX standards we should have.
Comment #4
nod_Comment #5
catchAdding a reference to #3452724-78: Navigation side bar and top bar should have appropriate aria labels - with the existing UI, the 'fake' navigation bar that you edit has the same aria labels as the 'real' navigation bar which could be additionally confusing for people using screenreaders.
Comment #7
gábor hojtsyDo we have a rough idea of design for this?
Comment #8
anybodyJust ran into this and I agree it should get removed. With the rise of Drupal Canvas we hopefully can get rid of heavy Layout Builder in several projects then. Navigation should not force enabling it.
https://github.com/SortableJS/Sortable is great!
Comment #9
anybodyRe
maybe this could be split into two parts: Removing the heavy dependency on layout_builder and the sorting library (asap) and improve the UI / UX step by step?
Comment #10
finnsky commentedI recently used https://github.com/atlassian/pragmatic-drag-and-drop in one project.
Works great.
Comment #11
gábor hojtsy@ckrina posted this a year ago:
So I never customized the navigation menu and therefore I did not know what is even possible and should be covered by a new UI. So I needed to go and check out how it works. I am trying it out with Drupal CMS here.
It is an eclectic mix of interactions to say the least :) I realize this is not an ideal interaction the authors of this module wanted, so the feedback should not be taken personally. But given this interaction, I have a feeling we can come up with better interactions. I agreethese are not good interactions regardless of the backend used. I've not used Layout Builder recently so maybe much of this is because of how Layout Builder works?
1. I go to a page in the admin menu that only has one single button to enable edit mode. The page has no use otherwise.
2. Once I click the button, the navigation becomes editable "in place" but I cannot actually do anything in-place, so this is kind of odd.
3. When I hover over the navigation I get a cross-hair mouse cursor, which indicates MOVE, but there is nothing to move, the interaction does not support me moving anything.
4. However each block gets a pencil icon with a contextual menu. That gives 3 options to configure the block, move the block or remove the block. Regardless of which one I choose the actual functionality appears in the other side of the window in the offcanvas tray (setings tray looks similar, but this is not the same, offcanvas tray is a built-in core feature).
5. The moving feature looks the most broken. There is a "Section 1" which sounds like an internal technical detail. I can't change the general layout of the navigation panel only pick items for the two actual regions. The whole experience looks visually broken with the crosshairs above the labels (regardless of viewport size, I tried on bigger screens) and "Section 1" prominent in the selection.
6. I can also add a block from a separate UI element, which gives me a filtered list of blocks again in a sidebar on the other side of the screen.
7. Regardless of what things I change in the right (dark) sidebar, the navigation is not updated until I save the sidebar. But it is updated when I save the sidebar, I don't need to go out of edit mode entirely to see the changes. This is a positive thing in this interaction.
My understanding is that with the new UI we want to:
Even if we only keep the two hardcoded regions and order inside them, we would still need to show config UI for the blocks in each and save their configs to render properly later, so the storage of all of the config may not be trivial to do in one issue with the UX. @catch may or may not have said that in #2, trying to what "only have to do the implementation once" meant there :)
Comment #12
gábor hojtsyForgot to attach the walk-through :D
Comment #13
gábor hojtsyDiscussed with @catch on Slack. He clarified that "only have to do the implementation once" in #2 meant that we should figure out the UX for customising Navigation on top of Layout Builder rather than porting the current UI to a non-LB backend (and THEN figuring out the new UI). The later would help accelerate removing Layout Builder from core, but LB is not close to being removed. Updating title to clarify this scope then, although it was already the scope explained in the issue summary.
Comment #14
gábor hojtsyI took a stab at vibe-coding a solution, this is only with claude prompts, no direct development. The ordering and dropping between regions within the section plugin works and as you can see in the navigation itself, it actually is saved properly. The edit, add and remove buttons show the dialogs but don't quite work :D This is the local diffstat for now:
Addition dialog looks like this but does not actually work yet:
Attached a video of how reordering and cross-region drag and drop works.
I can push this if anyone is interested :D
Comment #15
gábor hojtsyAttaching the vibe coded version as an interesting artifact, not to be considered as a change suggestion :) I realized the navigation module used to have a block module inspired UI to do this, so trying to dig that up now so we can maybe look at what humans already figured out ahead of us.
After all the vibe-coded solution had roughly 15% of its code base deal with the data formats layout builder needs (layout builder temp store for how the form works + section storage, etc). And it did not even have tests yet. So I don't know how much of this would actually break free of layout builder if we actually keep the backend and only replace the UI. For that I think the vibe-coding experiment gave some good directional info.
Comment #16
gábor hojtsyLooking at the prior art https://www.drupal.org/about/core/blog/the-new-navigation-module-and-lay... claims that 4000 lines of code were needed to reproduce the configuration of and storage of Navigation layout as custom block storage. The navigation block layout UI looked exactly like the block layout UI does now in core (but the code was a copy due to how the block UI and storage are both tied to a theme and navigation is not).
So I think there are 3 potential endgame directions at least for getting rid of the Layout Builder dependency:
Only in the first scenario are we looking at a new UI design (and lots of code to implement it). In the second scenario we are looking at a block UI refactor for it to be a reusable pattern UI. In the third scenario we are not even looking at having a UI.
Comment #17
gábor hojtsyI decided to take a stab at removing the UI to see what space does that give us but a lot of the underlying features are intertwined between customizing Layout Builder itself (eg. help text) and the UI of Layout Builder (eg. section add links being altered or section plugin filtering). So the more I removed the more it was apparent that there is almost nothing left once the layout builder UI integration is removed. So I decided to introduce a small config file instead with the block list. I did not find an existing core solution to list component sources like this, but kept using the core layout system (which does not require Layout Builder).
The UI still looks and works as-is just no UI to customize it. But the one API to customize it (config action) was ported to the new config. The old config action would not work due to how the old config is not possible to keep without removing the layout builder dependency, so this is effectively a new config action.
Update path intentionally not built yet so we can focus on looking at how a post-LB Navigation would look like and discuss if we even need a UI to customze elements if contrib can do it easily.
No screenshot because there is no UI change other than the UI customization being removed. 20 changed files with 312 additions and 882 deletions, so net 570 less lines so far AFAIS.
Comment #19
gábor hojtsyAdding LLM disclosure because although everything was heavily reviewed and inspected, it was done with LLM assistance nonetheless.
Comment #20
quicksketchInstead of a custom UI for a niche feature, why not use a simple UI with table drag and drop buttons in a table? This seems like it could be a simpler version of the admin/content/block page. Avoid any custom or new drag and drop libraries and just use the one (tabledrag) that's not going anywhere.
Comment #21
anybodyTotally agree with @quicksketch! Just wanted to write the same :)
Comment #22
gábor hojtsy@quicksketch: long time no see! Great stuff! I personally have nothing against tabledrag, @catch in #2 wrote "better to avoid tabledrag if we can I think", so I went with that. We still need a UI that allows to customize block config (eg. menu depths and such), add new blocks, move blocks between the two regions, so it gets to be near the complexity of the block UI at that point, no?
I also got claude do me a full plan on abstracting block UI so both block UI and Navigation can use it instead of duplicating it in block UI., but stopped short of executing it.
https://www.drupal.org/about/core/blog/the-new-navigation-module-and-lay... links to the issues when navigation still used to have a block UI like UI (which was fine IMHO, not flashy, but this is a very rarely used admin UI, so no flashy needed IMHO). I think core will still want to avoid duplicating that code (that post claimed 4k lines of code) to do the regions + edit + config + delete stuff all custom for navigation blocks which is the main elephant in the room I think.
Comment #23
catchI don't have a particular objection to using tabledrag but it's most necessary where you have three dimensions including tree depth rather than just vertical. Also doesn't give the visual drag and drop of the current interface (although there are other things about the current interface people don't like so maybe that's fine).
Comment #24
godotislateDoes it make sense to land @berdir's suggestino in #3521159-11: Move editing UI as-is from Navigation to dedicated new Navigation Layout module to remove runtime Layout Builder dependency to make the layout builder a optional dependency, used only for the admin UI for Navigation first? Seem likely that the navigation blocks won't be changed much, so LB can be uninstalled and reinstalled only when navigation changes are needed. It doesn't necessarily need to be a blocker here while determing what the new UI should look like.
Comment #25
catchI think that's a good idea, also above @Gabor seems to be considering the idea of moving the configuration UI to contrib, and it would enable that. For me I think a lot of sites will never customise the blocks, but also the ability to do so is a nice feature.
Comment #26
berdirFWIW, #3587499: Navigation stores plugin configuration with dependencies in a simple config object IMHO is an intermediate step and we're currently using that patch since layout builder is IMHO too heavy and has too many performance implications just to be able to press that button in the backend. But my understanding is that layout builder should eventually be removed from core, so we need plan to fully remove the dependency? Although moving the UI to contrib could also be an option, so core would just ship with the default configuration and customization would either require a contrib module or manual adjustments of the default config. Modules can also ship with their own default blocks (either through a custom hook now or through regular default config in #3587499: Navigation stores plugin configuration with dependencies in a simple config object).
Comment #27
gábor hojtsyInstead of building this custom UI or solving a custom UI on top of layout builder in core, I decided to back the issue in #3521159: Move editing UI as-is from Navigation to dedicated new Navigation Layout module to remove runtime Layout Builder dependency which is much simpler. It decouples Navigation from Layout Builder but keeps using the same storage format with a dedicated UI module to deal with customizing. But it keeps the UI module as-is currently (which is very confusing). That said it would be possible to move that one to contrib and also that separation means core does not install Layout Builder anymore by default. So marking as a duplicate of that, let's meet there!