t would be nice if there was an automated solution to always minify SVGs in core in the same way, because different tools optimize in different ways, using different default options, often stripping out important attributes. Applications that generate SVGs also generate their own different ways of structuring the SVG, so every time you pull an "optimized" file into an SVG editor, and save it again, it may make unrelated changes on the roundtrip back to optimized SVG. Therefore, the SVGs require manual edits after optimization to restore settings.
I think what is missing here is clear agreement to treat SVGs as implementation assets, not hand-curated visual code.
Also worth noting: running SVGs through optimizers like SVGO can make them harder to review and maintain. For example,
path="M11 0L14 3V16H2V0H11ZM3 15H13V4H10V1H3V15ZM11 3H12.5L11 1.5V3Z"
becomes
path="m11 0 3 3v13H2V0zM3 15h10V4h-3V1H3zm8-12h1.5L11 1.5z",
which is more compact but much less readable for quick diffs or manual review.
Isn't this kind of micro-optimization mostly obviated by gzip or brotli? I'm happy to be wrong, but these savings seem negligible in practice—especially considering that Drupal core’s own HTML output doesn’t aggressively strip whitespace, newlines, or indentation either.
Here is the RTF file I used for testing.
Here is a partial config export for what I've tested:
ckeditor5_paste_filter_pasteFilter:
enabled: true
filters:
-
enabled: true
weight: -18
search: '<o:p><\/o:p>'
replace: ''
-
enabled: true
weight: -17
search: '(<[^>]*) (style="[^"]*")'
replace: $1
-
enabled: true
weight: -16
search: '(<[^>]*) (face="[^"]*")'
replace: $1
-
enabled: true
weight: -15
search: '(<[^>]*) (class="[^"]*")'
replace: $1
-
enabled: true
weight: -14
search: '(<[^>]*) (valign="[^"]*")'
replace: $1
-
enabled: true
weight: -12
search: '<font[^>]*>'
replace: ''
-
enabled: true
weight: -11
search: '<\/font>'
replace: ''
-
enabled: true
weight: -10
search: '<span[^>]*>'
replace: ''
-
enabled: true
weight: -9
search: '<\/span>'
replace: ''
-
enabled: true
weight: -8
search: '<p> <\/p>'
replace: ''
-
enabled: true
weight: -7
search: '<p><\/p>'
replace: ''
-
enabled: true
weight: -6
search: '<b><\/b>'
replace: ''
-
enabled: true
weight: -5
search: '<i><\/i>'
replace: ''
-
enabled: true
weight: -4
search: '<a name="OLE_LINK[^"]*">(.*?)<\/a>'
replace: $1
-
enabled: true
weight: -3
search: '<p>\W*<br>\W* \W*<\/p>'
replace: ''
-
enabled: true
weight: -2
search: '<p>\W*<br>\W*<\/p>'
replace: ''
-
enabled: true
weight: -13
search: '(<[^>]*) (dir="ltr")'
replace: $1
-
enabled: true
weight: -1
search: (<br>)+
replace: '<br>'
-
enabled: true
weight: 0
search: (<p><br></p>)+
replace: '<p><br></p>'
-
enabled: true
weight: 1
search: '<br>\n'
replace: '<br>'
-
enabled: true
weight: 2
search: \n+
replace: '<br>'
jwilson3 → created an issue.
I'm not certain if I should change the $use_case to a new number
The use_case needs to be incremented to the lowest unused number. (Currently that would be 18).
Maintainer here. Thank you for the excellently written issue complete with MR!
I get the sense from the resulting markup that _label_help_append_title() is not ideal from an accessibility standpoint
You're probably right here. _label_help_append_title() is kind of the "worst case" scenario when nothing else works.
So what I recommend you do is to replace that with the other options to see if any of the other options work better and put the label help in the correct place, visually, on the form element.
_label_help_prepend_field_prefix($element, $content, $use_case);
_label_help_prepend_description($element, $content, $use_case);
_label_help_append_label_suffix($element, $content, $use_case);
If any of these work better than append_title, pls update to the MR. If not, leave a comment to that effect.
Thank you!
I added ddev and ddev-drupal-contrib to Svg Image Field contrib module and to Rivet contrib theme, but ddev-drupal-contrib advocates for also committing the custom ddev commands it provides, it does become burdensome to keep things updated as the drop keeps moving (between ddev updates, drupal updates, ddev-drupal-contrib updates).
instead of putting a complete ddev config inside each module, a single config file should be sufficient.
Ideally, in the future, boilerplate code for providing local development environments will be reduced.
Strong 1+. This seems like the ideal goal to shoot for. For example, it would be fantastic if ddev addons (like ddev-drupal-contrib) could be added to a single .ddev/config.contrib.yml file and not have to commit all those custom commands. Users could run ddev config
for their environment, and ddev pulls in the contrib file. Configuration overrides & customizations would go in .ddev/config.local.yml. Then, if the contrib module or theme itself needs custom DDEV commands, docker settings(?), or other things it could either commit them directly to the module's .ddev folder or create a separate ddev-addon-template, and add a dependency for their own ddev addon maintained in a separate codebase.
Fix issue summary HTML code readability.
I added a way to run lighthouse (locally, via the npm library) against all of the pages in the test site. I ran against the pages using a 1s delay and without any delay at all. Each run gives slightly different performance score but generally stays within a 2 point range in the mid nineties on each page, except for one. The "Ultimate LQIP" page can vary between a score of 100 AND then go consistently below 90 (as low as 87) in different runs. This must have something to do with the extra intermediate low-res image latency being what amounts to a double edged sword.
https://3523781-drupal-lqip.elementalidad.com/results.php
https://github.com/jameswilson/3523781-Drupal-LQIP/commit/245cbbc1d787a2...
Any chance we could get a 3.1 (or 3.0.1) release that includes this fix? This generates a lot of unnecessary noise in logs.
We are seeing deprecation warnings on cron run after updating to PHP 8.3.21 and clearing caches. These are only notice errors, I think, so we should still be fine. But there are about 500 of them after running cron from the admin UI.
Deprecated function: Creation of dynamic property
Drupal\feeds\Feeds\Item\SyndicationItem::$blog
is deprecated in Drupal\feeds\Feeds\Item\BaseItem->set()
(line 21 of modules/contrib/feeds/src/Feeds/Item/BaseItem.php).
Deprecated function: Creation of dynamic property
Drupal\feeds\Feeds\Item\SyndicationItem::$parent:field_group
is deprecated in Drupal\Core\Queue\DatabaseQueue->claimItem()
(line 150 of core/lib/Drupal/Core/Queue/DatabaseQueue.php).
Re: #15
adding the css .loaded class in inline js with a CSS rule is causing it to be the LCP again. So I don't think it's showing what the LCP would be for the different approaches.
- The
.loaded
class is used on several of the examples (SQIP, BlurHash, Ultimate LQIP, CSS-only LQIP) to change opacity with a smooth transition between the blurred placeholder and the full-res version. - For contrast, the LQIP WebP Smooth example uses a slightly different technique to change opacity smoothly, via an inline style
opacity:1
loaded via inline JSonload
, but the smoothing transition effect on the opacity is still defined in CSS (I don't believe the distinction between inline vs CSS ultimately matters for performance other than if your page has many images at some point you're sending down a lot of duplicitous bytes). - Finally, the basic examples (LQIP BMP, LQIP PNG, and LQIP WEBP) do not use any smoothing transition and just rely on browser loading to show the full-res image and overlay the low-res placeholder.
I don't think LCP is affected by the opacity change (both with or without smoothing effect). Rather, the problem with the LCP is that all examples except "Ultimate LQIP" use placeholders that have a Bits-Per-Pixel ratio far less than the recommended 0.05 which means LCP will always consider the repaint of the full-res image.
The takeaway is that we cannot effectively reduce LCP with the LQIP technique unless the placeholder image is large enough >0.05BPP. And for the image to be "large enough" to take over the LCP for the 1200 pixel wide hero in the example site, it has to be on the order of 40k in size, which IMO rules out the option of base64 inlining. This implies the LQIP must be a reference to another image file, and yet another request (with potential latency) to download the placeholder image, somewhat defeating the other intended of the goal of the LQIP (having something on screen fast, at page load time, ideally piggy-backed inline via the HTML request).
The data model and schema should support all fetchpriority
values — no question there. But I’d question the utility of exposing them at the image field formatter level.
Take the carousel example: there are (at least) two common patterns in Drupal:
- A multi-cardinality image field used as the image source, or
- A series of entities (e.g. paragraphs, ECK) each with a single image field.
In both cases, there's no reliable context at the field formatter or view mode level to determine which images are visible at page load. Exposing fetch priority there risks encouraging awkward architectures — e.g., splitting fields just to differentiate high
vs low
.
The complexity only increases with variations like random first slides or responsive carousels showing N slides. Handling these correctly almost always requires custom logic (alter hooks, preprocess).
A UI trying to cover this would have to offer nuanced options like:
- Unspecified (let browser decide)
- High (for LCP-critical images)
- Low (for images above the fold but not visible initially)
For multi-cardinality:
- First is high, others unspecified
- First is high, others low
- First N are high, rest low/unspecified
…which quickly gets unwieldy and still doesn’t address entity-based carousels.
In short, this might be better solved downstream (e.g., in preprocess) where real context exists.
Re: #15 (.loading class LCP issue) Thank you. I'll try to make sense of what you're saying and get to the bottom of this soon. But happy to have a PR if you know what the fix would be offhand. (The project is setup for DDEV running locally).
Re: #16 (SQIP) While SQIP is a "superior" image, there are two major reasons it is problematic: it is both resource intensive on the server-side and on the client-side. For the server-side, even if we were to reimplement `sqip` in PHP, I expect it will be a fair bit more resource intensive than simply scaling down a raster image to 8x8 and applying a simple box blur, which Drupal image styles can do for us OOTB today. On the client-side, the problem is the <g filter="blur(12px)">
which is applied via browser rendering. you can inspect https://3523781-drupal-lqip.elementalidad.com/images/hero.sqip.svg to see the file that was generated by the npm library.
The sqip command took about 2.6 seconds to run, used about 4 CPU cores, (thats >10s total compute time) for the 400kb image.
If you look at the animated GIF demonstrating the processing progression of the underlying binary used by sqip, it becomes fairly obvious this is intensive work: https://github.com/fogleman/primitive?tab=readme-ov-file#progression
For base64 images we need img-src data:, not entirely sure about SVG.
If you load SVG via data URI (e.g., src="data:image/svg+xml;base64,..."), then it would be covered by img-src data:
. But we'll also need to ensure any generated SVGs (especially via 3rd parties) are additionally XSS sanitized.
It's a good point to consider, and maybe we'd have to have a site-level configuration to pick using inline data uris, or additional requests for the thumbnails.
I set up a test site with a few LQUIP approaches to be able to test the visual load transitions (using a poor man's "delay" dropdown parameter to simulate latency and to actually see the LQIP for more than a brief second).
- A couple baselines (OOTB Drupal eager/lazy load settings).
- A couple basic LQIPs based on an inline square 8x8 thumbnail inspired by how Unsplash does it. Unsplash uses an inline BMP, but I also tested with inline PNG (same size as BMP), and an inline WebP which produced a much smaller inline payload as well as a slightly different visual blur (the BMP and PNG were visually equivalent). The key here is to add a simple box blur to the 8x8 thumbnail to avoid browsers rendering jagged edges between adjacent high-contrast pixels when scaling up the thumbnail to full-res size in the browser. I also tested without blur, and with larger thumbnails like 16x9, but none of these options look as visually appealing as the simple, blurred 8x8 square image.
- A LQIP WebP Smooth using an 8x8 blurred WebP inline thumbnail with smooth fade-in effect requiring an "onload" JS to transition from low- to high-res. IMO this is the clear winner to satisfy the visual perspective, architectural simplicity (no 3rd party deps aside from GD), and resource usage both client- and server-side.
- The Ultimate LQIP technique, which depends on 2 LQIPs and suffers from the twice the number of http requests.
- The Blurhash technique. Blurhas has an existing Drupal module, but calculating the blurhash is fairly resource intensive on the server-side, and the Drupal module doesn't have any caching. It also depends on the clever base83 hash being decoded with Javascript on the client-side, but the 3rd party library is a JS module which complicates usage for Drupal requiring the use of
import
and knowing the path to the library JS file. - A couple CSS-blur techniques including:
- a client-side blur of a small thumbnail. CSS blur applied to an image looks really bad around the edges of the image and is a non-starter.
- CSS-only LQIP technique. This has horrible CSS complexity to create the integer hash and the clien-side CSS gradient code to "decode" the integer hash. Also, the resulting effect of the grayscale gradient applied onto the image's calculated average color (which must be calculated server-side from the source image) look extremely simplistic compared to the 90-byte WebP thumbnail.
I had a look at LCP for each of these with WebPageTest and PageSpeed Insights, but couldn't find a solid winner emerge. In my tests, the "Ultimate LQIP" option had the worst LCP of them all on WebPageTest, so it appears that the LCP algorithm may vary based on what tool is being used. YMMV.
Ultimately, I think the LCP goal is possible but difficult to achieve for hero images with an LQIP approach alone, since you need twice the requests and the >BPP0.055 ratio ends up creating a fairly large image for the LCP (44-kilobyte) versus a simple 90-byte 8x8 thumbnail. However, it is also worth noting that none of the other approaches I've found that depend on a low-res blurred image or css-gradient will positively affect LCP since they inherently do not meet the minimum BPP ratio.
Looking forward to having others' thoughts, insights, and reviews.
Code here: https://github.com/jameswilson/3523781-Drupal-LQIP
Site here: https://3523781-drupal-lqip.elementalidad.com/
Because the blurhash is calculated inside a hook_preprocess_image()
function, unnecessary and costly regeneration of the hash happens after a Drupal cache rebuild or anytime the hook is executed such as during theme development when Twig caching is disabled. This severely hinders the theming process so as to be completely unusable on any page with an image of significant size.
Therefore, I would reiterate the importance of caching the generated blurhash either in the database (as issue summary suggests) or at the very least in the filesystem.
While the server-side blur is probably feasible, I don't think this precludes us considering tiny inline images (smaller than 20x20px).
Maybe next steps could be to create a few simple HTML page examples using the different approaches to see how Lighthouse LCP behaves.
Proposed tests:
- Baseline 1: JPG Hero image with lazy loading (Drupal's default option for all images).
- Baseline 2: JPG Hero image with eager loading.
- LQIP w/o CSS blur: Hero image with basic LQIP technique using a tiny base64 inline WebP placeholder image (a scaled down version of the hero, sizes to no more than 20×20 pixels).
- LQIP w/ CSS blur: Hero image with LQIP technique using a tiny base64 inline WebP placeholder image with client-side blur applied.
- SQIP
- Pure CSS LQIP.
Points to consider for fair comparison:
- payload size: inline WebP base64 versus inline SVG versus CSS (+ JS) size.
- placeholder render quality: a CSS blur will look good but could the <20×20px LQIP base64 payload image with no blur applied work (for reduced client-side processor power and shaving bytes off CSS)?
- load experience: is there any jank between the the visual shift from placeholder to full-res image? is it annoying enough to need a JS fade-in effect?
- Largest Contentful Paint score: Does each technique provide an efficient Lighthouse' LCP based on the placeholder, or do any of them get a longer LCP due to the full-res image loading in later?
- processing requirements: This will be hardest to confirm outright, but a tiny inline image with no CSS blur and minimal to no JS is more efficient than more complex solutions, and should count for something unless any of the previous points disqualify it.
I've rebased the MR on the latest 11.x in an attempt to clear unrelated CI failures...
Why not just inherit the one from Drupal core?
Said in another way, the concept of feature flags in Drupal are implemented as $config['module.settings']['enabled'] = FALSE;
. Those feature flags can then also optionally be exposed in the admin UI, to facilitate quick debugging. Ultimately though, adding a module settings configuration is the only realistic approach to solving this.
The patch in #29 does exactly this. If I had to criticize it at all, it would be to rename the setting 'purge' to 'enabled', to match the property name introduced in the FastlyPurger class.
I don't think it makes sense to have a label for an input that is hidden.
I totally agree with you. And my prior suggestion to convert to a fieldset w/ legend was rooted in this thinking. But a fieldset that only contains a hidden form element with a list of links also makes no sense semantically.
Semantically, the only thing I can think of that makes sense here is a <nav>
wrapper with a span or div tag around the label. Of course, at that point we would lose the default Drupal form element label styling, which makes this issue somewhat of a breaking change.
And sadly this is why I ended up with the current workaround to just add the id attribute to the hidden input.
Good point about latency. Thanks for clarifying it. I read that in the IS, but didn't understand, or at least it didn't sink in.
Thinking a bit more on server-side blur — to get a decent-looking blur baked into a raster image, the placeholder needs to be relatively large — e.g., 600x400 — unlike a tiny 15x10 that works fine when upscaled and blurred with CSS client-side. That larger size means more bytes, which makes base64 inlining less appealing due to HTML bloat. And even then, a 600x400 server-side blurred placeholder might still look blocky when upscaled to the final display size, especially on high-DPI screens.
For server-side blur, there’s a point of diminishing returns at around ~10% of the real image size or ~5KB in payload. A 600x400 pixel with heavy blur applied could be in the 10k to 40k range.
Taking https://csswizardry.com/2023/09/the-ultimate-lqip-lcp-technique/ into account, if a goal is to have the LQIP size get counted as the LCP and avoid the full image override that, then it seems like the CSS-only version might not work since it is only a 3x2 pixel image. On the other hand, I wonder how the inline SVG approach could work for the LCP calculation. the SQIP relies on client-side (CSS blur technique, which is processor intensive). It seems there are tradeoffs all around, the comment on https://github.com/axe312ger/sqip/issues/116 seems to suggest that doing the image blur on the server side would be beneficial, since lots of images with blur is CPU/GPU intensive client-side.
Big fan of SVG here, but thinking generally PHP and Drupal seem better positioned for a server-side raster-image LQIP approach, and as long as we can figure out an algorithm for a 0.0055BPP and ideally, a WebP conversion step, assuming available serverside.
The choices and tradeoffs come down to where to put the burden of
- One time server-side in memory raster with blur using tools natively available to PHP.
- One time server-side raster image without blur using tools natively available to PHP + CSS client-side blur.
- One time server-side vector image generation using non-native tooling (or writing a PHP library) + CSS client-side blur. NEEDS LCP validation.
Some references:
- the go SQIP implementation: https://github.com/fogleman/primitive
- the node SQIP implementation: https://github.com/axe312ger/sqip
- a modern node LQIP implementation: https://transitive-bullshit.github.io/lqip-modern/
- a php LQIP implementation https://gist.github.com/voduytuan/4a46e2ba5dcb353e0f60bdc483b1a5f3 which generates a base64 encoded string, that I'm suspicious of if we're trying to get a sufficient BPP ratio for really large above-the-fold hero images maybe it is better to just generate an image server side? Possibly the base64 vs image derivative could be a configuration option we do not expose in the UI but allow from config in code since figuring out which option to go with is fairly complicated.
Why was this change made?
With Lighthouse transitioning to "insights" instead of legacy "audits", fetchpriority is a new key signal for image delivery and LCP optimization. I hope this will stoke renewed interest and forward momentum on this issue.
Seems to me that theres not really a use case for specifying anything other than fetchpriority="high"
because the default would be no explicity fetch priority and therefore fallback source order. Images located earlier in source order that should be set explicitly "low" seems like an anti-pattern and a true edge case, since Accessibility best practices dictate that the DOM order should match rendered order.
I agree that preload should be kept separately from eager/lazy because preload adds a new HTML tag to the HEAD, as opposed to an attribute on the IMG tag.
Also, with Lighthouse now in the process of switching over to use "insights" instead of legacy "audits", there will also be forward momentum on the sister issue 📌 Add option for fetchpriority attribute within "image loading" area on image field formatter Active , which uses a similar checkbox toggle in the image field formatter UI. So when evaluating UI patterns it would be good to take into account that an ideal "final" product here would have two checkboxes, one for Preload and another for Fetch Priority.
Was about to pick this up, but neither throbber-active.gif nor throbber-inactive.png from core have been copied into the seven theme, meaning it inherits whatever core has already.
The only icon I see in the seven theme codebase is https://git.drupalcode.org/project/seven/-/blob/2.0.x/images/loading-sma... referenced only by jQuery UI Dialog.
https://git.drupalcode.org/project/seven/-/blob/2.0.x/css/components/dia...
The loading-small.gif is out of scope of this issue, therefore, I suggest closing this one and opening a follow-up issue to pull down the animated SVG I did for core in 📌 Update loading icon and use SVG Needs review .
I suggest starting over with a clean MR that just pulls in the SVG throbber that ended up getting committed to Core in #1974928: Update Drupal's default throbber icons → using the same approach from that issue for the Seven theme. No modernizer needed.
I'm clarifying what I understand to be "the ask" in the issue title.
I'm just curious why you couldn't do this with CSS though. Is there some default drupal behavior that looks broken without such an option built into the module?
Thanks for the review and rebase. Merge pipeline to 2.3.x in progress.
After:
jwilson3 → created an issue.
jwilson3 → created an issue.
jwilson3 → changed the visibility of the branch 3480807-update-dev-dependencies to hidden.
jwilson3 → changed the visibility of the branch 3480807-update-ddev to hidden.
jwilson3 → created an issue.
jwilson3 → created an issue.
@lincoln-batsirayi Try step debugging with Xdebug. Ideally configure it to break on exceptions. You can also try disable modules one by one to find a possible culprit. Sidenote: this kind of support question is somewhat out of scope of this issue, so you might take any follow-up questions elsewhere (eg #drupal-support in Slack). I'm still not really convinced that having an uncaught exception for a 403 ending up in logs is useful in this case either.
The only thing I can think of is that the label element is displayed here for visually consistent styling when this element appears alongside other exposed filter elements that *do* rely on the form element label.
jwilson3 → created an issue.
jwilson3 → created an issue.
Made several improvements to tablesort and views table, and views pager defaults.
jwilson3 → created an issue.
jwilson3 → created an issue.
Good points.
Needs exploration to determine how the ID attribute is set and passed into the form-element-label.html.twig. and also pass it into bef-links.html.twig.
The only other idea I can come up with is to change the #type to fieldset, in order to style a fieldset legend instead of having a stray label.
jwilson3 → created an issue.
jwilson3 → created an issue.
I flubbed the manual re-roll. here is a fix.
This needs an MR to be opened from the issue fork's branch.
Neither MR31 nor MR92 apply to the current stable branch 4.0.21, so here is a reroll that does.
Maybe there is heuristic approach, whereby the boost on the matched term field is so ridiculously high, you can safely group the bosted results as different from normal results from a numerical calculation. I wanted to see if there was an easy/known approach here. I haven't yet dug into the internals of how best bet works yet, but I presume architecturally it is similar to how other standard boosts work (maybe not though too).
jwilson3 → created an issue.
jwilson3 → created an issue.
The workaround for version 2.3.4 of this module is to completely remove the old module, and re-add it, to get the new version of the file name.
composer remove drupal/svg_image_field
composer install drupal/svg_image_field
This approach may not be practical for all users, especially if you depend on a continuous integration process and a separate server to build your composer dependencies for deployment.
Therefore, after discussion with @cmlara and @penyaskito Drupal contributors in the #maitainers channel on Drupal Slack, we think the solution architecture for a proper fix is to completely rename the plugin file to ScalableVectorGraphic.php
, to avoid the case sensitivity issue, and to add class aliases for the old versions of the file SVG.php
and Svg.php
.
@jwilson3, I don't think I understand what you are saying. The code for this merge request is what is triggering the eslint and stylelint errors at this point.
My bad. You're totally right. (Verified with a code review of the latest changes in the MR).
I still stand by my point in a comment above the CSS should avoid using an HTML id to target styling elements, and ideally (as mentioned in the issue summary) the button itself would be placed inline into the HTML and use classname instead of increasing specificity and using the button
in CSS. This would be a follow-up.
Code change looks good, IMO, but I haven't tested this using Wave WebAIM locally, so will not RTBC yet.
jwilson3 → created an issue.
The filter-tips.html.twig and accompanying template_preprocess_filter_tips() that ships with Drupal 11 do use Attributes appropriately and provide no default classes anymore.
Since there were no other templates identified that don't follow the recommended use of Attributes, this issue seems irrelevant at this point.
The current parent meta issue assigned in comment #28 seems irrelevant at this point, since the filter-tips.html.twig that ships with Drupal 11 has appropriate use of Attributes and provides no default classes anymore.
#25 📌 rework theme_filter_tips to use the new Attributes, and call theme('item_list) while we're at it Postponed: needs info :
we want to remove as many theme functions templates as possible that just duplicate things like e.g. a list and use suggestions instead.
This may be a valid point and relevant to this issue, but this seems extremely low-priority. The community has embraced Twig templates everywhere. Having this template isn't causing anyone issues. And is arguably more flexible allowing themers to completley swap out the simple nested list for a <table>, or a <details> or another component for improved readability of long filter tips.
I suggest closing this, but defer to more active core contributors for consensus.
Sadly the longer this goes without getting in the more of these kinds of unrelated formatting changes to pass CI tests are going to happen.
I'd almost say we need to create a separate ticket to pass CI (stylelint and eslint), then rebase this issue once that one gets in.