vuetifyjs / vuetifyjs/vuetify

[Bug Report][3.4.1] Automatic color variations override manually defined colors

Open Beginner friendly
#18,702 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

E: theme T: bug
Dominant language
TypeScript
Stars
41k
Forks
7.1k
Avg merge
1d 21h
Merged PRs (30d)
11

Description

Environment

Vuetify Version: 3.4.1
Vue Version: 3.3.8
Browsers: Chrome 119.0.0.0
OS: Mac OS 10.15.7

Steps to reproduce
  1. Define a custom theme:
const customTheme = {
  dark: false,
  colors: {
    primary: '#00456c',
    secondary: '#c8c8c8',
    'primary-darken-1': '#f00',
  },
}
  1. Use the custom theme and let vuetify create color variations:
export const vuetify = createVuetify({
  theme: {
    defaultTheme: 'customTheme',
    themes: {
      customTheme,
    },
    variations: {
      colors: ['primary', 'secondary'],
      darken: 2,
      lighten: 2,
    },
  },
})
  1. Use the color variant primary-darken-1 on, for example, a button:
<v-btn color="primary-darken-1" class="mt-3">Hello world primary-darken-1!</v-btn><br />

The button will use the darkened primary color and not the manually defined primary-darken-1 color.

Expected Behavior

The manually defined color should be used. In the example the button background should be red.

Actual Behavior

The automatic color variation overrides the manually provided color. In the example the button background is a darker variant of the primary blue.

Reproduction Link (updated)

https://play.vuetifyjs.com/#...

Other comments

The cause of this is probably because there is no check if a color already exists in that line: https://github.com/vuetifyjs/vuetify/blob/master/packages/vuetify/src/composables/theme.ts#L228

for (const variation of (['lighten', 'darken'] as const)) {
  const fn = variation === 'lighten' ? lighten : darken
  for (const amount of createRange(parsedOptions.variations[variation], 1)) {
    theme.colors[`${name}-${variation}-${amount}`] = RGBtoHex(fn(parseColor(color), amount))
  }
}

This could be prevented by checking if the key already exists and only adding it if it isn't there already:

for (const variation of (['lighten', 'darken'] as const)) {
  const fn = variation === 'lighten' ? lighten : darken
  for (const amount of createRange(parsedOptions.variations[variation], 1)) {
    const colorkey = `${name}-${variation}-${amount}`
    if(!(colorkey in theme.colors)){
      theme.colors[colorkey] = RGBtoHex(fn(parseColor(color), amount))
    }
  }
}

My use-case for that is using the color variations as a default but also being able to override some variations with colors from a user customizable theme.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in packages/vuetify/src/composables/theme.ts around line 228 and reproduce the issue with the customTheme and variations configuration from the report. Verify that an explicitly defined primary-darken-1 color is preserved instead of being replaced by the generated variation, using the linked reproduction to confirm the button background.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
design, frontend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.