Problem/Motivation
Current Problem: When fields allow multiple values (such as text fields, file uploads, references, etc.), Drupal automatically outputs the widget in a table with tabledrag functionality to allow users to reorder the values. While this reordering capability can be useful in some contexts, it creates significant problems for many use cases:
User Impact:
- Frontend developers struggle to style multivalue fields consistently with other form elements due to the forced table structure
- UX designers find it difficult to implement custom designs when tables with drag handles are always present
- Site builders have no control over whether reordering is actually needed for their specific content workflows
- End users are presented with unnecessary complexity when field order doesn't matter for their use case
Current Behavior: All multivalue fields automatically get:
- Table-based markup with thead/tbody structure
- Drag handles for reordering
- Weight fields (hidden by default but present in form structure)
- Complex JavaScript for tabledrag functionality
- CSS that assumes table-based layout
Expected Behavior: Site builders should be able to choose whether multivalue fields need reordering capability, with those that don't need it getting simplified markup and styling that's easier to theme.
Specific Pain Points:
- CSS frameworks and design systems struggle with the table-based markup
- Mobile responsiveness is harder to achieve with forced table layouts
- Accessibility can be impacted by unnecessary complexity
- Performance overhead from tabledrag JavaScript when not needed
- Form styling becomes inconsistent between single and multivalue fields
Steps to Reproduce
- Create a content type with any multivalue field (text, file, reference, etc.)
- Configure the field to allow multiple values
- Go to the form display settings for that content type
- Notice that there are no options to disable reordering for the multivalue field
- View the node add/edit form
- Observe the table markup, drag handles, and tabledrag JavaScript being loaded
- Attempt to style the field consistently with single-value fields
- Notice the difficulty in applying consistent styling due to table structure
Proposed Resolution
High-Level Approach: Add a new "Orderable" checkbox to the widget settings for all multivalue fields. When unchecked, the field will render with simplified markup without tables, drag handles, or weight fields.
Key Implementation Decisions:
- Configuration Location: Add the setting to individual widget instances rather than field definitions, allowing the same field to have different behaviors on different form displays
- Default Behavior: Keep current behavior as default (orderable enabled) to maintain backward compatibility
- Scope: General solution that works for all multivalue widgets rather than widget-specific implementations
- Markup Strategy: Use a simple div-based container structure when reordering is disabled
- Theme Integration: Ensure the simplified markup works well with existing themes and is easier to style
Technical Implementation:
- Modified the base
WidgetBaseclass to add the orderable setting - Created new
field-multiple-value-without-order-form.html.twigtemplate for simplified rendering - Updated theme system to conditionally render table vs. simple markup
- Implemented clean configuration schema inheritance using
field.widget.settings.base - Ensured form validation and submission work correctly without weights
Configuration Schema Approach:
Implemented Base Type Inheritance pattern for optimal maintainability:
# Single source of truth field.widget.settings.base: type: mapping mapping: orderable: type: boolean label: 'Orderable' # Widgets inherit explicitly field.widget.settings.string_textfield: type: field.widget.settings.base mapping: size: ... placeholder: ...
Benefits:
- Single definition replaces 25+ individual orderable settings
- No schema pollution for widgets that don't need ordering
- Automatic inheritance for future widgets
- Follows Drupal configuration best practices
- Improved designer/developer experience for styling forms
- Better mobile and responsive design capabilities
- Reduced complexity and better performance when reordering isn't needed
- Maintains full backward compatibility with existing sites
- Provides granular control per widget instance
Remaining Tasks
Implementation Status: ✅ COMPLETE
The following tasks have been completed:
- Technical architecture - Base inheritance pattern implemented
- Template implementation - New template created and integrated
- Widget base modifications - WidgetBase updated with orderable setting
- Configuration schema - Clean inheritance using field.widget.settings.base
- Widget coverage - 19 widgets across core and modules updated
- Theme integration - Core themes (Claro, Stable9) support added
- Comprehensive testing - 22+ tests with 280+ assertions passing
- JavaScript integration - Conditional tabledrag loading
- Form processing - Handles missing weights correctly
- Accessibility review - Simplified markup meets standards
- Performance validation - JavaScript and rendering improvements confirmed
- Security review - Form processing security validated
- Documentation - Implementation details documented in tabledrag.md
Current Tasks (if any):
Theme integration
- Ensure compatibility with core themes
- Add appropriate CSS classes for styling hooks
- Document theming changes
Documentation updates
- Update form API documentation
- Add change record for the new functionality
- Update developer documentation with examples
- Accessibility review - Ensure simplified markup meets accessibility standards
- Performance testing - Validate JavaScript and rendering improvements
- Security review - Confirm form processing security with modified workflow
- Final user acceptance testing
- Potential contrib module compatibility testing
User Interface Changes
Widget Configuration (Before): Currently, multivalue widget settings show standard widget-specific options but no control over reordering behavior.
Widget Configuration (After): A new checkbox "Orderable" appears in the widget settings for any field configured to allow multiple values, with summary text showing "Orderable: Yes/No".
Form Rendering Changes:
<div class="field-multiple-table">
<table>
<thead>
<tr>
<th>Value</th>
<th>Order</th>
</tr>
</thead>
<tbody>
<tr class="draggable">
<td>[field widget]</td>
<td>[drag handle + weight field]</td>
</tr>
</tbody>
</table>
</div>
**After (Orderable Disabled):**
<div class="field-multiple-container">
<div class="field-multiple-item">
[field widget]
</div>
<div class="field-multiple-item">
[field widget]
</div>
</div>
Visual Impact: Forms with reordering disabled have cleaner, more consistent styling that matches single-value fields and is much easier to customize with CSS.
API Changes
New Widget Setting:
WidgetBase::defaultSettings()includes'orderable' => TRUEWidgetBase::settingsForm()includes the orderable checkbox for multivalue widgetsWidgetBase::settingsSummary()shows orderable status
Theme System Changes:
field-multiple-value-without-order-form.html.twigtemplate for simplified rendering- New theme hook suggestions available for non-reorderable multivalue fields
- Additional CSS classes for improved styling hooks
- Template selection logic in theme preprocessing
Form Processing:
- Form submission handling updated to work without weight values when reordering disabled
- Validation adjusted to not expect weight fields in simplified mode
- JavaScript conditionally loads tabledrag functionality
Configuration Schema:
- New
field.widget.settings.basetype for clean inheritance - 19 widget definitions updated to inherit from base type
- Reduced schema complexity from 125+ lines to ~25 lines
Backward Compatibility:
- No breaking changes - all existing functionality remains unchanged
- Sites can opt-in to simplified markup on a per-widget basis
- Default behavior maintains current table-based rendering
Data Model Changes
None - This change only affects form rendering and widget configuration. No database schema changes are required.
Configuration Schema Changes: Widget configuration entities store the new orderable boolean setting through Drupal's existing configuration system without database structure changes.
Release Note Snippet
Multivalue field widgets now include an "Orderable" setting that allows site builders to disable the table-based drag-and-drop interface when field ordering is not needed. This provides cleaner markup that is easier to style and improves mobile responsiveness for multivalue fields. The feature uses a clean configuration schema inheritance pattern and maintains full backward compatibility.
How it looks
Widget settings

Default orderable multivalue email field

Not orderable multivalue email field

File field examples

OUTDATED:
Before:

After:
![]()
Setting:

Disclosure: I used Claude to help write this issue summary, and work with me on the code contributions I made - I did check the code and test it myself - foxtrotcharlie
| Comment | File | Size | Author |
|---|---|---|---|
| #165 | tabeldrag-with-empty-field.png | 47.69 KB | dries |
| #162 | 2264739-162.patch | 192.48 KB | jzavrl |
| #159 | file-field-examples.png | 312.82 KB | foxtrotcharlie |
| #157 | email-not-orderable2.png | 57.81 KB | foxtrotcharlie |
| #156 | email-orderable.png | 52.47 KB | foxtrotcharlie |
Issue fork drupal-2264739
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:
- 2264739-disable-field-drag-and-drop-D11
changes, plain diff MR !11595
- 2264739-orderable-multifield-d11
changes, plain diff MR !14184
- 2264739-D10
changes, plain diff MR !2851
- 2264739-allow-multiple-field
changes, plain diff MR !450
- 11.x
compare
- drupal-2264739-D10
compare
- drupal-2264739-2264739-D10
compare
Comments
Comment #1
dcam commentedThis is a feature request and would need to be applied to the next development version.
Comment #2
grndlvl commentedOK here is the first pass for 8.0.x b/c the feature was wanted for 8.0.x.
Will need to re-create for 8.1.x-dev and write tests.
Comment #3
grndlvl commentedRe-roll for latest release
Comment #4
grndlvl commentedRe-roll for latest.
Comment #5
swentel commentedLove the idea, let's see what the bot thinks of it.
We'll probably want a test for this.
Comment #7
grndlvl commentedAllowing fallback to orderable when a contrib module overrides the WidgetBase::formMultipleElements() method.
Comment #8
grndlvl commentedUpload the right one...
Comment #12
jonathanshawRun tests
Comment #14
jonathanshawTest errors are all/mostly coming from "orderable missing schema". Looks like field config schema needs updating.
Comment #15
tacituseu commentedRe-roll.
Comment #16
tacituseu commentedConfig fixes, NR just to check.
Comment #18
tacituseu commentedComment #20
tacituseu commentedCan't say I agree with the implementation, doesn't really fit with 'cardinality', 'revisionable', 'translatable'.
Feels like it could be simpler, contained within
Drupal\Core\Field\WidgetBaseand'settings'. Thoughts ?Comment #21
tacituseu commentedComment #24
tacituseu commentedComment #26
tacituseu commentedSeems
AssertConfigTrait::assertConfigDiff()is order sensitive.Still not ready, will make interdiff for green patch.
Comment #28
tacituseu commentedComment #30
tacituseu commentedShould be green.
Comment #31
Munavijayalakshmi commentedThis should go through $this->t().
Comment #32
Munavijayalakshmi commentedComment #33
tacituseu commented@Munavijayalakshmi: Thanks.
Adding screenshots.
Comment #34
tacituseu commentedComment #35
jonathanshawI love the idea of this, but shouldn't this be a widget setting (as stated in the IS) rather than a field setting? I can imagine that sometimes for the a field I might want a simplified widget without ordering for everyday use, but in a more advanced administrator UI I might want to allow ordering. Worth discussing at least.
And if it is a field setting, I'd expect to find it next to the cardinality settings.
Comment #36
tacituseu commented@jonathanshaw: the original issue was for 7.x and there is a widget patch buried with it so it might explain IS.
I'm not aware of any architectural reasons it is so low level and expressed similar opinion in #20.
So far just restored the functionality of the patch from #8, certainly needs some discussion and direction from field subsystem maintainers.
Comment #37
tacituseu commentedAlternative/simpler implementation attached, moved it to widget settings, no schema changes.
Doesn't cover file and image fields, neither did original.
Edit:
The reasoning behind moving it into widget settings was that I felt that placing it near cardinality (in storage settings) would imply something about the underlying storage: that you can't count on the order items will be returned from database.
What I needed though was purely visual/widget side ability to get rid of that horrid table on fields that don't need reordering.
Also, the drawback of this patch is that it relies on each widget calling its parent in
::settingsForm(), which will cause troubles with contrib (it falls back to non-orderable in those cases).Comment #39
jonathanshawComment #40
tacituseu commentedInitial pass for schema, also fixed settings summary for fields with cardinality = 1.
Comment #42
tacituseu commentedComment #44
tacituseu commentedComment #47
k4v commentedI really like this patch! It kinda works for me on a first test.
One thing I wonder: I have custom field type with multiple properties, and now I'm missing a wrapper around each item. What would be the best approach here?
Comment #48
tacituseu commentedI had a rant somewhere about there being no concept of a component in Drupal's markup (collection of widgets/elements acting together as a single input), it is visible in core especially around issues with date/date range modules.
For now in custom/complex/mixed field types I add inside
FieldWidget::formElement()something like:You can also use
hook_field_widget_form_alterto do this.I also have a newer version of the patch that supports file and image fields running on dev, but I'm spread a bit thin at the moment so not sure when I'll get back to this.
Comment #49
k4v commentedThanks that sounds good. If you post the current version I could test it, maybe work on it at the sprint weekend...
Comment #50
k4v commentedHere is a change that makes the patch apply to 8.4.4.
Comment #51
k4v commentedComment #52
tacituseu commented@k4v: Thanks, I checked the code in dev, file/image is very 'raw' at the moment, need to refactor it before posting, will post in a day or two.
Comment #54
tacituseu commentedComment #55
tacituseu commentedDidn't touch tests.
Comment #57
tacituseu commentedSome test fixes.
Comment #59
tacituseu commentedShould be green.
Comment #61
tacituseu commentedComment #63
tacituseu commentedComment #64
k4v commentedthank you!
Comment #65
mohit1604 commented@tacituseu , Thanks for the patch. But while applying patch#63 terminal shows following error:
error: patch failed: core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/BooleanCheckboxWidget.php:33
error: core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/BooleanCheckboxWidget.php: patch does not apply
error: patch failed: core/modules/comment/config/schema/comment.schema.yml:14
error: core/modules/comment/config/schema/comment.schema.yml: patch does not apply
Comment #66
tacituseu commented@Mohit Malik: Couple of string/comment changing commits went in recently, as a feature request it is rolled for 8.5.x where it applies cleanly.
Comment #67
tacituseu commentedUpdating IS with new settings screenshot.
Comment #69
k4v commentedPatch #63 works very well for me, would like to see this in core :).
Comment #70
k4v commentedComment #72
k4v commentedThis is a reroll for Drupal 8.5.4, I removed the test additions from the now deprected base class.
Comment #73
k4v commentedReroll for 8.6.x
Comment #74
hchonovWe need an update path to add the new setting to existing form display config entities.
There is a similar update in #2863188: Hardcoded result size limit in the entity reference autocomplete widget., which could be adjusted for the current issue. Additionally the Config Entity Updater should be used in the update - https://www.drupal.org/node/2949630 .
Comment #76
k4v commentedJust a small fix: The twig template was missing from the core/module/system/templates folder.
This patch is only for 8.5.x.
Comment #77
k4v commentedComment #79
k4v commentedUpdated for 8.6
Just changed the name of the Test core/modules/field/src/Tests/FormTest.php to /core/modules/field/tests/src/Functional/FormTest.php
Comment #80
k4v commentedComment #83
pasqualleMulti column fields look bad when the row separator is removed.
Comment #85
pasqualleRerolled (should apply clearly to 8.8.0-beta1)
Comment #86
pasqualle#85 has wrong end of file
Comment #87
pasqualleTrying to fix some test failures
Comment #89
handkerchiefThank you for all your work.
It's impressive how such a "small" feature means such an effort and over such a long period.
"Best" workaround that works for me:
Credit to: http://www.intheloftstudios.com/blog/remove-tabledrag-field-drupal-using...
Comment #90
joseph.olstadThe patch still applies cleanly to 8.9.x, however it needs work to run on 9.0.x and 9.1.x , some of the test files have moved around.
We need this for WCAG compliance, the tabledrag has a link that is empty and wcag flags this as an issue.
So I'm looking at this patch because I want to disable tabledrag on a multifield fieldset.
Comment #91
jonathanshawComment #92
sanjayk commentedComment #93
sanjayk commentedReroll the patch for D9, will work on test cases.
Comment #94
sanjayk commentedComment #95
sanjayk commentedComment #96
shaktikComment #97
shaktikThe patch #94 no longer to appled. so I have re-roll the patch for D9.
Comment #99
rudam commentedJust want to share some love to the ones in this thread, I love you all 😂
Comment #100
jonathanshawComment #102
raman.b commentedResolving failed test cases from #97
Comment #103
jonathanshaw#37 says:
the drawback of this patch is that it relies on each widget calling its parent in ::settingsForm(), which will cause troubles with contrib (it falls back to non-orderable in those cases).
We should fall back to orderable for backwards compatibility.
Also we need an upgrade path per #74.
I do wonder whether we should split the issue. Add the theme component in one issue, then make it the default for all widgets in another (tricky!) issue.
Comment #104
jonathanshawComment #105
pasquallereroll
Comment #107
dieterholvoet commentedI moved the latest patch to an issue fork and added support for the #description_display. I also removed the
element wrapping the label, I don't see why that one is needed. Finally, I added a copy of the template to Claro with the new description class.
Comment #109
abhijith s commentedApplied patch #105 on 9.2.x and it works fine.The orderable checkbox is displayed in the display settings after applying this patch.Also the functionality is working fine.
Before patch;

After patch:

RTBC +1
Comment #110
huskey786 commented#105 Patch fails to apply on 8.9.13, had to go back to #87 which worked.
Comment #111
System Lord commentedI patch manually and not going to attempt this one. I'll have to wait for it in a release. Meanwhile I'm using this. Throw it into your browser inspector and see if it does the job.
Comment #113
jedihe commentedThe snippet from the external link (with a slight modification) at #89 works for me, thanks @handkerchief! There is, however, a small problem: all draggable tables in multi-value fields (even nested under paragraphs) are removed. For a selective removal, I modified it like this:
Comment #114
lexfunk commentedI just simply pulled the patch from the latest merge request which seems to be applying alright to 9.2.4.
Running a test against 9.3.x
Comment #117
seanbI updated the MR and merged in 9.3.x but not sure how I can change the MR target. I don't seem to have permissions to do that. In hindsight, I think only the creator of the MR can do that, so sorry about that. @Pasqualle could you maybe update the target branch?
Attached is a 9.3.x patch as well.
Comment #119
dww@seanB: I think Gitlab / d.o integration is smoother if you rebase MRs against the target branch, instead of merging back into the fork. That's why this issue is now very hard to read with what Gitlab is saying between #116 and #117. There's always a tag saved on every force push to git.d.o, so we always have the full history.
Thanks,
-Derek
Comment #120
dwwp.s. Yes, there's sadly no way for most contributors to update Gitlab MR metadata, including changing the target branch or resolving threads. That requires the author of the MR or one of the core committers. We are at least discussing this as part of the Gitlab acceleration initiative, but it's not yet clear if we can do anything about it.
Comment #121
seanbYeah, sorry about that, probably should have created a new MR for 9.3. Any suggestions on what I can do to fix this particular MR and undo the mess I created?
Comment #122
stopopol commented+1
Comment #123
pasqualleChanged the target branch and hard reset (with force push) to the commit mentioned in comment #107
The diff seems to be ok-ish.
https://git.drupalcode.org/project/drupal/-/merge_requests/450/diffs
Need manual rebase and conflict fix.
Not sure about the MR history, if it will create any issue when merged.
Comment #125
pasqualleComment #127
pasqualleCreated new branch and MR against D10.1
Todo: There are 2 new themes in D10: olivero and starterkit_theme where the new template file should be added.
Comment #129
driskell commentedRebased both MR for 9.5.x and 10.1.x.
Remaining tasks:
- Add tests
- Add template file for olivero
- Add template file for starterkit_theme
Comment #130
anneke_vde commentedAttached is the patch version of MR 450 for those working with composer patches.
Comment #131
driskell commentedHi @anneke_vde
You can access the composer patch you need for an MR by visiting the changes tab and adding “.diff” or “.patch” to the end of the url: https://git.drupalcode.org/project/drupal/-/merge_requests/2851/diffs.diff
Edit: It has been rightly pointed out this isn't a reliable URL to add to composer patches, and would need downloading and storing instead. Whereas patch files are consistent and reliable to use as a composer patches URL if using that method.
Comment #132
jedihe commented@Driskell: the .diff url is very practical, but I think it'll return a different diff as the MR gets commits pushed. In order to ensure a build doesn't end up having code you didn't properly test/review, it's better to have an actual patch file.
Comment #133
driskell commented@jedihe Ah quite right! I see now, thanks. I normally download the patch and commit it and hadn't considered that approach of direct URL. I'll edit my comment to clarify in case others see it.
Comment #134
anneke_vde commentedThanx for the clarification, that was indeed the reason why I uploaded the patch file.
Comment #136
rodrigoaguileraAdded a rebase removing the template for "stable" (only stable9 remains in D10) and an attempt at fixing the failing test from last run.
Only did it for 10.1.x since is the only branch that is receiving features now.
Another thing the proposed code is not handling is the existing widgets that will be rendered as non-orderable after the change.
I found this change
https://git.drupalcode.org/project/drupal/-/commit/2c3f5743df1dc19515258...
That sets the
tooltipas a mandatory setting for Drupal 11.We should something similar here:
Since there is no layout builder for forms modes there is no need for a hook_post_update.
Comment #139
dan_metille commentedSeems that patch does not apply to D10.2
Comment #140
abelassI confirm, patch is not applicable to 10.2
Comment #141
wilfred waltman commentedThe patch did not apply on 10.2 because the field.widget.settings.language_select are moved from language.schema.yml to core.entity.schema.yml.
Here is a patch that does apply to 10.2
Comment #142
abelassThanks @Wilfred Waltman , applies now perfectly
Comment #143
alvarito75 commentedConfirming #141 patch works for
Comment #144
andypostComment #145
mjmorley commentedThe patch from #141 works well for me on Drupal 10.2.7 and PHP 8.2.12. I have extended the patch to only build the _weight field when "orderable" is set to TRUE.
Comment #146
mjmorley commentedMy last patch missed the template /core/modules/system/templates/field-multiple-value-without-order-form.html.twig so this one adds that in
Comment #149
foxtrotcharlie commentedHere's the patch for the merge request https://git.drupalcode.org/project/drupal/-/merge_requests/11595
Comment #150
balagan commentedReroll for branch 10.5.x.
Comment #152
eelkeblokThe patch in #150 unfortunately resolves the merge conflict between this patch and D10.5 incorrectly. The conflict is that the FileWidget settingform introduces a warning if the upload progress PHP extension is not available. The patch in #150 removes that again.
Here is a patch for D10.5 that retains the notice.
Comment #153
jaydarnellPatch #152 appears to be working well for Drupal 10.5.1 so far.
Comment #154
d.fisher commentedPatch #152 working for me too.
Comment #155
foxtrotcharlie commentedComment #156
foxtrotcharlie commentedComment #157
foxtrotcharlie commentedComment #158
foxtrotcharlie commentedComment #159
foxtrotcharlie commentedComment #162
jzavrl commentedRerolled the patch from #149 to work with latest 11.3. New MR at https://git.drupalcode.org/project/drupal/-/merge_requests/14184.patch and attached is the patch file.
Comment #165
dries commentedGood feature. I’ve always found it strange that tabledrag was required.
Even when there are zero items and nothing to reorder, tabledrag is still present. See screenshot. Why show it until you can actually reorder something? Fixing that might be beyond the scope of this issue, but figured I'd mention it here.
Comment #166
foxtrotcharlie commented