Skip to content

fix(Avatar): resolve height/width calculation for AvatarGroup and custom size classes#6008

Open
maximepvrt wants to merge 7 commits intonuxt:v4from
maximepvrt:fix-avatar-height-width
Open

fix(Avatar): resolve height/width calculation for AvatarGroup and custom size classes#6008
maximepvrt wants to merge 7 commits intonuxt:v4from
maximepvrt:fix-avatar-height-width

Conversation

@maximepvrt
Copy link
Contributor

@maximepvrt maximepvrt commented Feb 8, 2026

🔗 Linked issue

❓ Type of change

  • 📖 Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • 👌 Enhancement (improving an existing functionality)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

📚 Description

This PR fixes an issue when UAvatar is used by size defined in UAvatarGroup, the height and width were not correctly resolved. It also enables the generation of correct height and width for custom size attributes, allowing the component to dynamically adapt to any Tailwind size-{n} class.

These attributes are critical for Nuxt Image to fetch and serve the asset at the correct dimensions, preventing layout shifts and optimizing bandwidth.

Changes

Dynamic Extraction: Added a computed property to extract the numerical value from Tailwind size-{n} classes

Example
Using <UAvatar class="size-64" /> will now correctly pass height="256" and width="256" to the image renderer, even if a :size prop is also present or inherited from a group.

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

@github-actions github-actions bot added the v4 #4488 label Feb 8, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 8, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Avatar.vue: Replaces a static sizePx mapping by computing a rootClass from ui and props, parsing a size-<number> token from that class, multiplying the number by 4 to derive pixel size, and falling back to 32 if parsing fails. The root element's class binding now uses rootClass instead of calling ui.root inline. Error handling and rendering paths are unchanged. renovate.json: adds top-level Renovate config entries timezone: "Europe/Paris" and schedule: ["* 6-9 * * 1"].

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (17 files):

⚔️ renovate.json (content)
⚔️ src/runtime/components/Avatar.vue (content)
⚔️ src/runtime/components/Input.vue (content)
⚔️ src/runtime/components/InputMenu.vue (content)
⚔️ src/runtime/components/Select.vue (content)
⚔️ src/runtime/components/SelectMenu.vue (content)
⚔️ src/runtime/components/Textarea.vue (content)
⚔️ src/runtime/types/input.ts (content)
⚔️ src/runtime/types/utils.ts (content)
⚔️ test/components/__snapshots__/AvatarGroup-vue.spec.ts.snap (content)
⚔️ test/components/__snapshots__/AvatarGroup.spec.ts.snap (content)
⚔️ test/components/__snapshots__/Empty-vue.spec.ts.snap (content)
⚔️ test/components/__snapshots__/Empty.spec.ts.snap (content)
⚔️ test/components/__snapshots__/FileUpload-vue.spec.ts.snap (content)
⚔️ test/components/__snapshots__/FileUpload.spec.ts.snap (content)
⚔️ test/components/__snapshots__/PageLogos-vue.spec.ts.snap (content)
⚔️ test/components/__snapshots__/PageLogos.spec.ts.snap (content)

These conflicts must be resolved before merging into v4.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main change: fixing height/width calculation in Avatar component for AvatarGroup and custom size classes, which matches the core modification to Avatar.vue.
Description check ✅ Passed The description is directly related to the changeset, explaining the bug fix for UAvatar height/width resolution and dynamic sizing from Tailwind classes, which aligns with the Avatar.vue modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/runtime/components/Avatar.vue`:
- Around line 73-78: The computed sizePx logic is setting numericValue to null
which passes the NaN guard and causes 0 instead of the 32 fallback and also
causes a TypeScript type error for parseFloat's parameter; update the size
extraction in the sizePx computed (rootClass.value, sizeClass) so you pass a
string to Number.parseFloat (e.g. use sizeClass?.split('-')[1] ?? '') and assign
numericValue as a number (use Number.parseFloat result, not null), then use
Number.isFinite(numericValue) to decide return numericValue * 4 or the fallback
32; this fixes the TS error and ensures null/undefined/non-numeric values fall
through to the 32 default.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/runtime/components/Avatar.vue`:
- Line 75: The code assigns a bare NaN to numericValue which violates
unicorn/prefer-number-properties; update the expression that computes
numericValue (the const numericValue = ... using sizeClass and
Number.parseFloat) to return Number.NaN instead of the bare NaN when sizeClass
is falsy or split yields no numeric part, i.e., replace occurrences of NaN with
Number.NaN so numericValue uses the Number namespace per the rule while
preserving existing fallback behavior in the sizeClass -> Number.parseFloat
logic.

@benjamincanac benjamincanac changed the title fix(UAvatar): resolve height/width calculation for AvatarGroup and support custom size classes fix(Avatar): resolve height/width calculation for AvatarGroup and custom size classes Feb 12, 2026
@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 16, 2026

npm i https://pkg.pr.new/@nuxt/ui@6008

commit: 7bc7bea

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🤖 Fix all issues with AI agents
Verify each finding against the current code and only fix it if needed.


In `@renovate.json`:
- Around line 5-6: The renovate.json change introduces unrelated configuration
keys ("timezone" and "schedule") into an Avatar bug-fix PR; remove these two
keys (the "timezone" and "schedule" entries) from this branch and either revert
them from the PR or move them into a separate branch and open a dedicated PR
containing only the renovate.json changes so the Avatar fix PR contains only
avatar-related diffs.
🧹 Nitpick comments (1)
🤖 Fix all nitpicks with AI agents
Verify each finding against the current code and only fix it if needed.


In `@renovate.json`:
- Around line 5-6: The renovate.json change introduces unrelated configuration
keys ("timezone" and "schedule") into an Avatar bug-fix PR; remove these two
keys (the "timezone" and "schedule" entries) from this branch and either revert
them from the PR or move them into a separate branch and open a dedicated PR
containing only the renovate.json changes so the Avatar fix PR contains only
avatar-related diffs.
renovate.json (1)

5-6: Unrelated change bundled into an Avatar bug-fix PR.

These Renovate config additions (timezone and schedule) are unrelated to the Avatar height/width fix described in the PR objectives. Consider splitting them into a separate PR for a cleaner commit history and easier bisecting.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@renovate.json` around lines 5 - 6, The renovate.json change introduces
unrelated configuration keys ("timezone" and "schedule") into an Avatar bug-fix
PR; remove these two keys (the "timezone" and "schedule" entries) from this
branch and either revert them from the PR or move them into a separate branch
and open a dedicated PR containing only the renovate.json changes so the Avatar
fix PR contains only avatar-related diffs.

Copy link
Member

@benjamincanac benjamincanac left a comment

Choose a reason for hiding this comment

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

Good catch!

The class parsing approach introduces a regression though. Avatars with non-numeric size classes like size-full (used in FileUpload) all fall back to width="32" instead of their correct values. You can see it in the FileUpload snapshots dimensions are now all 32.

A simpler fix would be to use the size computed from useAvatarGroup instead of props.size in the lookup and only fall back to class parsing for custom sizes:

const sizePx = computed(() => {
  const sizeMap: Record<string, number> = {
    '3xs': 16, '2xs': 20, 'xs': 24, 'sm': 28,
    'md': 32, 'lg': 36, 'xl': 40, '2xl': 44, '3xl': 48
  }

  const mapped = sizeMap[size.value || 'md']
  if (mapped) return mapped

  const classes = ui.value.root({ class: [uiProp.value?.root, props.class] })
  const sizeClass = classes.split(' ').find(c => /^size-\d/.test(c))
  if (sizeClass) {
    const num = Number.parseFloat(sizeClass.split('-')[1] ?? '')
    if (!Number.isNaN(num)) return num * 4
  }

  return 32
})

This fixes the AvatarGroup bug without regressing FileUpload.

@maximepvrt
Copy link
Contributor Author

maximepvrt commented Feb 18, 2026

@benjamincanac, your code currently returns early because of the default 'md' value, which makes the size class analysis unreachable when size is undefined.

const mapped = sizeMap[size.value || 'md']
if (mapped) return mapped

I think we should check for the CSS class first and use the sizeMap only as a fallback. Otherwise, if a user overrides the avatar size via theme, the computed value remains incorrect.

@maximepvrt
Copy link
Contributor Author

maximepvrt commented Feb 19, 2026

@benjamincanac Just to clarify regarding the fileUpload component in my initial PR: whether we set the width and height to 32px or 36px, those values aren't actually used to fetch an optimized image because we aren't using Nuxt Image but a native img component.

Furthermore, the image currently has a size-full sizing applied. As a result, when it's rendered in the grid layout, it stretches to over 100px anyway, completely ignoring the 32px/36px dimensions.

Capture d’écran 2026-02-19 à 11 44 10 Capture d’écran 2026-02-19 à 11 44 38

Is it worth keeping a default size with size-full, at the risk of getting a blurry, pixelated image if Nuxt Image eventually generates a 32px version ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v4 #4488

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants