Skip to content

fix(VBadge): make wrapper element use tag prop for valid HTML nesting (Fixes #23093) - #23095

Open
waterWang wants to merge 1 commit into
vuetifyjs:masterfrom
waterWang:fix/23093-vbadge-wrapper-tag
Open

waterWang wants to merge 1 commit into
vuetifyjs:masterfrom
waterWang:fix/23093-vbadge-wrapper-tag

Conversation

@waterWang

Copy link
Copy Markdown
Contributor

Summary

When VBadge is used inside VBtn (as shown in the VBadge documentation), the rendered HTML is invalid because VBadge hardcodes <div class="v-badge__wrapper"> inside VBtn's <span class="v-btn__content"> wrapper. The W3C validator reports:

Element "div" not allowed as child of element "span" in this context.

Fix

Make the v-badge__wrapper element use the tag prop instead of being hardcoded as a <div>. When tag="span" (or any phrasing-valid tag) is passed, both the root element and the wrapper element produce valid phrasing content.

Before (invalid HTML)

<span class="v-btn__content">
  <div class="v-badge">
    <div class="v-badge__wrapper">   <!-- INVALID: div inside span -->

After (valid HTML with tag="span")

<span class="v-btn__content">
  <span class="v-badge">
    <span class="v-badge__wrapper">  <!-- VALID: span inside span -->

Backward compatibility

Default tag="div" produces identical output to before: div > div > ...

Fixes #23093

The v-badge__wrapper element was hardcoded as a div, which produces
invalid HTML when VBadge is nested inside VBtn (whose content wrapper
is a span - phrasing content). The W3C validator reports:

  Element div not allowed as child of element span in this context.

Fix: use the tag prop for both the root element and the wrapper, so
that when tag=span (or any phrasing-valid tag) is passed, both
elements produce valid phrasing content.

Fixes vuetifyjs#23093
style={ props.style }
>
<div class="v-badge__wrapper">
<props.tag class="v-badge__wrapper">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be fine if we are convinced tag on <v-badge> is never used in real life. Otherwise it is too risky

@J-Sek

J-Sek commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

We have badges within buttons and tabs across handful of examples. Assuming we don't bail on the risk of regression, those should be updated in the same PR.

@BatLeDev

Copy link
Copy Markdown
Contributor

The three examples with a badge inside a button or a tab, for the update @J-Sek asked for — I checked every <v-badge> nested in a <v-btn>/<v-tab> across packages/docs/src, there are exactly these:

  • examples/v-badge/prop-content.vue (3 badges, inside v-btn stacked)
  • examples/v-badge/prop-dot.vue (2 badges, inside v-btn stacked)
  • examples/v-badge/misc-tabs.vue (3 badges, inside v-tab)

All eight wrap only a v-icon or plain text, so adding tag="span" makes them valid with no other change.

Worth noting for anyone tempted to change the default instead: it would not work. examples/v-badge/misc-customization.vue wraps a v-avatar (a div), so a span default would just move the invalidity there. Keeping tag="div" as the default and opting in to span inside phrasing contexts is the right call.

The same defect on VChip is now tracked separately in #23103, with a fix proposed in #23106 — there it needs no tag discussion, since the chip root is already a span.

@waterWang I have those three example updates ready in waterWang#1 — a single commit on top of this PR's branch, so merging it into fix/23093-vbadge-wrapper-tag lands everything here in one piece.

@J-Sek
J-Sek force-pushed the master branch 2 times, most recently from 630451f to 3d3f418 Compare September 17, 2026 10:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug Report][4.1.8] VBadge renders divs inside VBtn's span, producing invalid HTML

3 participants