Remove legacy browser support from js.module.css [#3514748] | Drupal.org
Skip to search
Can we use first and third party cookies and web beacons to
understand our audience, and to tailor promotions you see
Remove legacy browser support from js.module.css
Fixed
Project:
Drupal core
Version:
11.x-dev
Component:
CSS
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Reporter:
catch
Created:
21 Mar 2025 at 20:54 UTC
Updated:
22 Apr 2026 at 18:02 UTC
Jump to comment:
Most recent
Most recent file
Problem/Motivation
js.module.css includes some classes for older browsers as of 2023
#3404218: Table filter creates jank (layout shift) on page load
shows pretty broad support across multiple releases now.
Steps to reproduce
Proposed resolution
Remove
.js .js-hide
and .
js .js-show
rules from js.module.css
Decide whether rules/selectors within
@media (scripting: enabled)
media query need updating for specificity. Options:
Leave as is
.js-hide.js-hide
and
.js-show
Use !important on .js-hide rule:
.js-hide {
display: none !imporant;
.js-show {
display: block;
add
[class]
to selector:
.js-hide[class] {
display: none;

.js-show[class] {
display: block;
For any CSS changes, need to regression test:
Views wizard per
#10
Table filters per
#3404218: Table filter creates jank (layout shift) on page load
Navigate to the page in question (in this case /admin/modules), and open developer tools. Go to the network tab and set throttling to "Fast 3G") and ensure that "Disable cache" is checked.
Reload the browser and notice how the "filter" pops in and shifts the layout.
Apply the patch.
Test again and note how the "filter" is there on page load and does not "pop in".
Test the page without JavaScript (you can disable this in dev tools)
Test the page on an older browser that doesn't support this new feature. The behavior should not change.
Test the page on other browsers to ensure it works as expected.
Remaining tasks
User interface changes
NA
Introduced terminology
NA
API changes
NA
Data model changes
NA
Release notes snippet
NA
Comment
File
Size
Author
#52
3514748-nr-bot_8072uu6j.txt
553 bytes
needs-review-queue-bot
#40
Screenshot 2026-01-20 at 11.52.41 AM.png
69.55 KB
godotislate
#32
Extend _ drupal-11 (1).mp4
607.39 KB
ahsannazir
#21
Screenshot 2025-04-17 at 10.23.59 AM.png
31.96 KB
bernardm28
#21
Screenshot 2025-04-17 at 10.23.24 AM.png
39.46 KB
bernardm28
#17
Screen Recording 2025-04-16 at 10.43.53 AM.mov
549.26 KB
godotislate
#10
Screenshot 2025-04-16 at 15.16.45.png
111.25 KB
lendude
Issue fork
drupal-3514748
Show commands
Start within a Git clone of the project using the
version control instructions
Add & fetch this issue fork’s repository
Or,
if you do not have
SSH keys set up on git.drupalcode.org
Add & fetch this issue fork’s repository
3 hidden branches
3514748-only-scripting
plain diff
MR
!14393
Check out this branch for the first time
Check out existing branch, if you already have it locally
3514748-specifity
plain diff
MR
!11855
Check out this branch for the first time
Check out existing branch, if you already have it locally
3514748-simplify-js.module.css
changes
plain diff
MR
!11567
Check out this branch for the first time
Check out existing branch, if you already have it locally
About issue forks
Comments
Comment
#1
21 March 2025 at 20:54
catch
created an issue. See
original summary
or
to post comments
Comment
#2
catch
he/him
commented
21 March 2025 at 20:57
Status:
Active
» Needs review
or
to post comments
Comment
#3
21 March 2025 at 23:53
smustgrave
opened
merge request !11567
or
to post comments
Comment
#4
smustgrave
commented
21 March 2025 at 23:54
Status:
Needs review
» Reviewed & tested by the community
Seems pretty straight forward.
or
to post comments
Comment
#5
catch
he/him
commented
22 March 2025 at 09:29
Title:
Simplify js.module.css
» Remove legacy browser support from js.module.css
or
to post comments
Comment
#6
4 April 2025 at 09:06
nod_
made their first commit to this issue’s fork.
or
to post comments
Comment
#7
4 April 2025 at 09:11
nod_
committed
f9be36f0
on
11.x
Issue #3514748 by catch: Remove legacy browser support from js.module....
or
to post comments
Comment
#8
nod_
French
Lille
commented
4 April 2025 at 09:12
Status:
Reviewed & tested by the community
» Fixed
Committed
f9be36f
and pushed to 11.x. Thanks!
or
to post comments
Comment
#9
4 April 2025 at 09:12
nod_
closed
merge request !11567
or
to post comments
Comment
#10
lendude
Dutch
Amsterdam
commented
16 April 2025 at 13:19
Status
File
Size
new
Screenshot 2025-04-16 at 15.16.45.png
111.25 KB
This seems to have broken/started showing some buttons that need to be hidden in the Views wizard:
Should open a follow up or is this a revert and fix?
or
to post comments
Comment
#11
16 April 2025 at 13:36
nod_
committed
99423203
on
11.x
Revert "Issue #3514748 by catch: Remove legacy browser support from js....
or
to post comments
Comment
#12
nod_
French
Lille
commented
16 April 2025 at 13:37
Status:
Fixed
» Needs work
reverted for now, thanks for finding the issue!
or
to post comments
Comment
#13
16 April 2025 at 13:37
catch
opened
merge request !11855
or
to post comments
Comment
#14
catch
he/him
commented
16 April 2025 at 13:43
Cross-posted with nod_, it's a CSS specificity issue - Claro's .button display: inline-block; is overriding the .js-hide.
Pushed a commit to
which seems to be enough.
or
to post comments
Comment
#15
catch
he/him
commented
16 April 2025 at 13:43
Status:
Needs work
» Needs review
or
to post comments
Comment
#16
lendude
Dutch
Amsterdam
commented
16 April 2025 at 14:10
Not confident enough in my css skills to mark RTBC, but checked, and it fixes the issue in the Views wizard at least
or
to post comments
Comment
#17
godotislate
he/him
commented
16 April 2025 at 17:51
Status:
Needs review
» Needs work
Status
File
Size
new
Screen Recording 2025-04-16 at 10.43.53 AM.mov
549.26 KB
The views wizard issue is fixed, but the change in MR 11855 causes a regression from
#3404218: Table filter creates jank (layout shift) on page load
. The filter is popping in again on /admin/modules when I use Chrome inspector to disable cache and throttle to 3G. This doesn't happen on HEAD.
Screen recording is attached.
or
to post comments
Comment
#18
catch
he/him
commented
17 April 2025 at 11:49
Status:
Needs work
» Needs review
Issue tags:
Needs manual testing
That's a good additional test case...
The reason .js .js-hide doesn't work is because the .js class is added by... JavaScript so it completely undermines the point of the original MR. Obvious once you realise it, but wasn't when I tried it out to fix the views issue.
I could not think of another good way to add additional specificity, so went for
!important
This works for both test cases, but let's be honest I haven't written much CSS either for money or for free since about 2009 so there might be a better way.
Explicitly tagging for manual testing just in case I messed up the steps to reproduce too.
or
to post comments
Comment
#19
godotislate
he/him
commented
17 April 2025 at 13:50
Manually tested both the views wizard and modules filter and they both look good now. I'm slightly concerned about the use of
!important
, but I'm not familiar enough with what's going on there to offer any alternatives w/r/t specificity. +1 for RTBC if others are good with the
!important
or
to post comments
Comment
#20
bernardm28
commented
17 April 2025 at 14:16
To overcome some experience builder past bugs, we would add an attribute to increase the specificity.
Say.
.js-show[class] {
display: block;
That could make it more specific than Claro and avoid using !important
or
to post comments
Comment
#21
bernardm28
commented
17 April 2025 at 14:28
Status
File
Size
new
Screenshot 2025-04-17 at 10.23.24 AM.png
39.46 KB
new
Screenshot 2025-04-17 at 10.23.59 AM.png
31.96 KB
Before this fix, without the !important
After the fix with [class]
or
to post comments
Comment
#22
godotislate
he/him
commented
17 April 2025 at 14:29
Looking back at comments from
#3404218: Table filter creates jank (layout shift) on page load
Original patch in #2 had this:
@media (scripting: enabled) {
/* Extra specificity to override previous selector. */
[class] .js-hide {
display: none;

.js-show {
display: block;
Suggestion was made for this instead in #8:
Why not
.js-hide.js-hide
like we do usually when we need to increase specificity?
or
to post comments
Comment
#23
bernardm28
commented
17 April 2025 at 14:48
Both are valid solutions, but DrupalCMS is leaning more on attributes [class].
So I would say preference leans towards class attributes.
or
to post comments
Comment
#24
godotislate
he/him
commented
17 April 2025 at 15:18
From the IS, the goal is to remove the additional classes in the selectors since
@media (scripting: enabled)
is well supported. In which case, seems to me that the selectors within the media query should work well enough as is (and I've just tested to confirm), and the only thing needed is to remove the rules outside the media query.
That reduces the diff size, and the use of
.{CLASS}.{SAMECLASS}
selectors is used often in core, so I think that part can be left as is.
I have to say, this one in media-library.pcss.css is pretty amusing:
.media-library-item .ajax-progress.ajax-progress.ajax-progress
or
to post comments
Comment
#25
kwiseman
commented
17 April 2025 at 19:28
The
.js-hide[class]
approach seems like the most concise, specific option without using
!important
, and I'm also in favor of it. However, that approach would select .js-hide with any other class, not just its duplicate, but I'm not sure how much of a problem that is if it's working for Drupal CMS.
or
to post comments
Comment
#26
markconroy
commented
18 April 2025 at 07:14
I think this is a good example of when we would use
!important
In this instance, it's !important that when the class
.js-hide
is present that the item concerned is hidden.
Perhaps we can use
!important
just for the hiding part and not for the showing part. For
.js-show
we may not want
display: block
all the time (sometimes we might want flex/grid/inline-block/etc) so !important should not be used for that.
After that I think @godotislate "double class" idea is probably best.
.js-hide.js-hide
. If we use
.js-hide[class]
it might affect other classes if they are present.
or
to post comments
Comment
#27
smustgrave
commented
1 May 2025 at 15:31
Issue summary:
View changes
Status:
Needs review
» Needs work
Sorry to be that guy, since this did cause an issue before can we update the summary fully. Tried to get it started.
or
to post comments
Comment
#28
godotislate
he/him
commented
1 May 2025 at 16:51
Issue summary:
View changes
or
to post comments
Comment
#29
godotislate
he/him
commented
1 May 2025 at 16:53
Issue summary:
View changes
or
to post comments
Comment
#30
catch
he/him
commented
1 May 2025 at 16:56
Issue tags:
Needs frontend framework manager review
Tagging this for front end framework manager review, assuming the options are functionally (almost?) identical, this feels like more of a style preference/consistency decision.
or
to post comments
Comment
#31
nicxvan
commented
16 September 2025 at 02:37
Status:
Needs work
» Needs review
I think this is technically supposed to be needs review.
or
to post comments
Comment
#32
ahsannazir
commented
13 October 2025 at 06:38
Status
File
Size
new
Extend _ drupal-11 (1).mp4
607.39 KB
I don't see any layout shift due to Filter shows a little late. I followed the steps as per IS
Attaching screen capture
or
to post comments
Comment
#33
catch
he/him
commented
18 January 2026 at 18:08
Opened
#3568172: Move .js-show and .js-hide libraries to their own library and load them when js is on the page
which could be the next step after this one.
or
to post comments
Comment
#34
18 January 2026 at 19:14
catch
opened
merge request !14393
or
to post comments
Comment
#35
catch
he/him
commented
18 January 2026 at 19:16
Maybe I'm missing something, but I don't see why we can't use media-scripting: none to hide .js-show, which means we don't need to worry about overriding specificity and things either. Opened a new MR just in case this is silly, have
not
run manual CSS regression test yet but will try to do that next time I'm at computer properly.
or
to post comments
Comment
#36
jwilson3
Ecuador
commented
20 January 2026 at 08:02
I like the approach in #35, as its forward thinking. That being said, the media scripting functionality is still relatively new (MQ Level 5) adopted in modern browsers around 2023. Checking
caniuse media scripting
shows we meet the "Baseline" at around 89% of global browsers. But for the other 11%, the way the MR is written might have a regression. On browsers that don't support media scripting, both media query blocks get ignored/dropped, and .js-show becomes visible by default. (i.e., "assume old browsers have JS enabled") Is this intentional?
Also, I can't make sense of the test failure, or why we have a test like this:
Asserting StylesheetBytes 979 is greater or equal to 1000 and is smaller or equal to 2000
Failed asserting that 979 ( is equal to 1000 or is greater than 1000 ) and ( is equal to 2000 or is less than 2000 ).
or
to post comments
Comment
#37
catch
he/him
commented
20 January 2026 at 09:08
But for the other 11%, the way the MR is written might have a regression. On browsers that don't support media scripting, both media query blocks get ignored/dropped, and .js-show becomes visible by default. (i.e., "assume old browsers have JS enabled") Is this intentional?
Yes this is OK. Browser requirements for core are listed here:
and it's well covered by the browsers we support. It's also fine I think to default to assuming js is enabled these days since disabling JavaScript is rare now compared to 15-20 years ago.
Test failure is a performance test, it's designed to measure changes like this, so that we gradually reduce our page weight (and the other things it measures) over time, or only increase them when necessary.
updating it now.
That test was at around 7kb when it was added, and now under 1kb through incrementally going through
#2880237: [meta] Refactor system/base library
or
to post comments
Comment
#38
20 January 2026 at 09:08
catch
changed the visibility of the branch
3514748-specifity
to
hidden
or
to post comments
Comment
#39
jwilson3
Ecuador
commented
20 January 2026 at 09:55
Nice. I wanted to check the tugboat preview environment, but it is marked failed. I tried a rebuild which also failed.
or
to post comments
Comment
#40
godotislate
he/him
commented
20 January 2026 at 19:54
Status:
Needs review
» Needs work
Status
File
Size
new
Screenshot 2026-01-20 at 11.52.41 AM.png
69.55 KB
Tested MR 14393 locally, and it fails the regression test per #10. This is on MacOS Tahoe Chrome 143.0.7499.193. The buttons do not appear when I test on main.
or
to post comments
Comment
#41
catch
he/him
commented
21 January 2026 at 09:12
That's the same specificity issue discussed above, pushed a commit for
.js-hide[class]
which works for me locally.
or
to post comments
Comment
#42
catch
he/him
commented
21 January 2026 at 11:13
Status:
Needs work
» Needs review
or
to post comments
Comment
#43
godotislate
he/him
commented
21 January 2026 at 16:21
Latest commit fixes the View wizard, and there's no regression on the module filter in the IS. Though it seems we've circled back to whether
.js-hide.js-hide
(existing Drupal core convention) vs
.js-hide[class]
(new Drupal CMS convention? see #20) is preferred.
or
to post comments
Comment
#44
catch
he/him
commented
21 January 2026 at 20:45
I personally think
.js-hide.js-hide
looks like someone made a typo, where .js-hide[class] is more intentional. However I have no idea what's the 'better' CSS (and there's also !important too).
If we don't care that much, we could go ahead and open a follow-up to settle on a convention to use across core. Would be nice to start saving the bandwidth, even if it's miniscule it's more or less every request to every Drupal site.
or
to post comments
Comment
#45
jwilson3
Ecuador
commented
21 January 2026 at 21:04
Normally, I would never argue for the use of !important, but .js-hide/.js-show cascade warfare seems different than other places.
The cascade problems arise when we're doing things like
display:block
but we want that element to have (for example)
display: flex
and have to resort to CSS specificity hacks.
But the refactor from catch has cleverly allowed us to removed all
display: block
instances.
ISTM that now that .js-hide/.js-show is used exclusively for
hiding
content in certain scenarios, it should take precedence over everything else and therefore
display: none !important
could be safe to use here, no? What am I missing?
or
to post comments
Comment
#46
godotislate
he/him
commented
21 January 2026 at 21:08
I think we're just back at the outstanding "Needs frontend framework manager review".
or
to post comments
Comment
#47
catch
he/him
commented
21 January 2026 at 21:12
@jwilson3 yes that's right - we've got rid of display:block so the only issue we have now is we need our rules to win in all cases.
I'm actually going to switch to !important because that's exactly the behaviour we want, even though the feature is discouraged it's a real feature and feels like the right place to use it. All three approaches work so we can always change it later.
General note that in the process of thinking about this issue, I think we can make it so this file is only added conditionally too, doesn't affect the contents of the CSS, only how we organise it
#3568172: Move .js-show and .js-hide libraries to their own library and load them when js is on the page
for the follow-up.
or
to post comments
Comment
#48
markconroy
commented
22 January 2026 at 15:01
@catch I know I mentioned in
#15
above that
!important
seems right here, but often we want to change something from
display: none;
to
display: flex;
(or grid, etc) (rather than block), and that
!important
could come back to bite us.
I'm not saying we should not do it, but just wanted to raise it as a consideration.
or
to post comments
Comment
#49
22 January 2026 at 15:01
Version:
11.x-dev
» main
Drupal core is now using the
main
branch as the primary development branch. New developments and disruptive changes should now be targeted to the
main
branch.
Read more in the announcement
or
to post comments
Comment
#50
jwilson3
Ecuador
commented
28 January 2026 at 22:17
No strong opinion either way, but note: this MR removes all display: block usage and standardizes on display: none (optionally reinforced with !important). This is so that now, out of the box,
display: flex
(or grid or block) applied to a div that has js-show will Just Work ™ as you intended!
If on the other hand someone wants to (for whatever crazy reason) explicitly do the inverse of what is coded (i.e. show something marked as js-hide when JS is enabled, or hide something marked as js-show when JS is disabled), the correct approach is to either A) swap js-hide with js-show and vice-versa or B) remove the js-hide/js-show utility class and replace it with your own class and styles. (I hope this makes sense to everyone, it boils down to logic tied to classnames matching display intent).
Using display: flex !important to override those utilities works, but it’s effectively opting out via a specificity hack, so the burden is intentionally on the developer when going against the pattern.
Without !important reinforcement in the MR, the minor risk is that if something is coded with high specificity eg
:root .mything { display: flex }
the js-hide/js-show logic will never take effect.
Edit: updated my comment for clarity. 2026/4/1
or
to post comments
Comment
#51
smustgrave
commented
27 March 2026 at 23:54
Haven't been able to get ahold of a frontend manager. Not sure how to best move this one forward.
or
to post comments
Comment
#52
needs-review-queue-bot
commented
11 April 2026 at 00:09
Status:
Needs review
» Needs work
Status
File
Size
new
3514748-nr-bot_8072uu6j.txt
553 bytes
The
Needs Review Queue Bot
tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the
Drupal Contributor Guide
to find step-by-step guides for working with issues.
or
to post comments
Comment
#53
catch
he/him
commented
11 April 2026 at 16:56
Status:
Needs work
» Needs review
@smustgrave this can be RTBC without an FEFM review (assuming people think it's RTBC, but for me I think we have enough consensus, or at least lack of strong opinions, on the current solution), it just needs FEFM sign-off before it gets committed.
or
to post comments
Comment
#54
smustgrave
commented
11 April 2026 at 17:05
Status:
Needs review
» Reviewed & tested by the community
Issue tags:
Needs manual testing
In that case think it’s good to go.
or
to post comments
Comment
#55
catch
he/him
commented
14 April 2026 at 09:59
iirc this removes a style recalculation - because the .js class is added by JavaScript, but apparently I failed to add that information to the issue and it's some time since I checked this. I think this makes sense anyway just to trim the CSS weight, but if my memory is correct it should result in a small browser rendering improvement on top of that.
or
to post comments
Comment
#56
nod_
French
Lille
commented
14 April 2026 at 12:13
Issue tags:
Needs frontend framework manager review
+1 from me, !important is made for this kind of things.
or
to post comments
Comment
#57
22 April 2026 at 17:09
godotislate
closed
merge request !14393
or
to post comments
Comment
#58
22 April 2026 at 17:09
godotislate
committed
b7156dd5
on
main
refactor: #3514748 Remove legacy browser support from js.module.css

By...
or
to post comments
Comment
#59
22 April 2026 at 17:09
godotislate
committed
5b744138
on
11.x
refactor: #3514748 Remove legacy browser support from js.module.css

By...
or
to post comments
Comment
#60
godotislate
he/him
commented
22 April 2026 at 17:13
Status:
Reviewed & tested by the community
» Patch (to be ported)
Committed and pushed
b7156dd
to main and
5b74413
to 11.x. Thanks!
Should this go to 11.3.x? Moving to Patch to be ported in case we want it.
or
to post comments
Comment
#61
catch
he/him
commented
22 April 2026 at 18:02
Version:
main
» 11.x-dev
Status:
Patch (to be ported)
» Fixed
I think I would leave this just in 11.x/11.4, it's low risk but also not a bug fix. There's maybe a tiny chance it affects how someone is overriding these classes, probably not though.
or
to post comments
Comment
#62
22 April 2026 at 18:02
Now that this issue is closed,
review the
contribution record
As a contributor, attribute any organization that helped you, or if you volunteered your own time.
Maintainers, credit people who helped resolve this issue.
or
to post comments
Contribution record
Parent issue
Add child issue
clone issue
Referenced by
#2902084: Prevent FOUC depending on availability of javascript
#3568172: Move .js-show and .js-hide libraries to their own library and load them when js is on the page
Infrastructure management for Drupal.org provided by
Need a Drupal 7 extended support partner? Consider Tag1.
News items
News
Planet Drupal
Social media
Sign up for Drupal news
Security advisories
Jobs
Our community
Community
Services
Training
Hosting
Contributor guide
Groups & meetups
DrupalCon
Code of conduct
Documentation
Documentation
Drupal Guide
Drupal User Guide
Developer docs
API.Drupal.org
Drupal code base
Download & Extend
Drupal core
Modules
Themes
Distributions
Governance of community
About
Web accessibility
Drupal Association
About Drupal.org
Drupal is a
registered trademark
of
Dries Buytaert