Storybook: Vue + Vuetify theme not working

Created on 30 Sep 2018  路  23Comments  路  Source: storybookjs/storybook

Bug or support request summary

Calling Vue.use (Vuetify {theme: { primary: , etc.}}) is not working - a component that tries to use that theme does not take on the color, for instance.

_Please provide issue details here - What did you expect to happen? What happened instead?_

Component should use theme color in rendering. It does not.

Steps to reproduce

  • Create a minimal project with Vue cli (2 or 3)
  • in the config, import Vue and Vuetify
  • add a Vue.use() line, specifying a theme
  • create a component (VBtn works), that uses a color in the theme (primary, for instance))
  • create a story to invoke the button.

VBtn doesn't take on the color. (in my test app, it does when run from dev/serve)

Please specify which version of Storybook and optionally any affected addons that you're running

  • @storybook/vue 3.4.11
  • @storybook/addons 3.4.11
  • @storybook/addon-actions 3.4.11
  • @storybook/addon-links 3.4.11

Affected platforms

  • _If UI related, please indicate:

    • chrome 69.0.3497.100 (Official Build) (64-bit), MacOS High Sierra

  • _If dependency related, please include relevant version numbers

    • vue - latest version (2.5.17)

    • vuetify - latest version (1.2.5)

Screenshots / Screencast / Code Snippets (Optional)

Example component:

<template>
  <v-btn round
    color="primary">
    <slot></slot>
  </v-btn>
</template>

<script>
export default {
  name: "test-button",
}
</script>

App file invoking the component:

  <v-app>
    <v-layout column justify-center>
      <v-layout row justify-center align-center>
         <test-button @click="testBtnClicked">
           Click It
         </test-button>
      </v-layout>
    </v-layout>
  </v-app>

Vue/Vuetify setup in config.js:

import Vue from 'vue';
import 'vuetify/dist/vuetify.min.css';
import Vuetify from "vuetify";
import colors from 'vuetify/es5/util/colors';

Vue.use(Vuetify, {
  theme: {
    primary: colors.indigo.base,
    info: colors.blue.lighten2,
    accent: colors.green.lighten1,
    error: colors.red.darken2
  }
});

Story for the TestButton:

import { storiesOf } from "@storybook/vue";

import TestButton from "./TestButton.vue";

storiesOf("TestButton", module)
  .add("default", () => ({
    template: '<test-button>Click Me</test-button>',
    components: {TestButton}
  }))
vue has workaround inactive question / support

Most helpful comment

I have the problem too.

After reading vuetify's code, seems the generation of CSS, and injection of the theme is made in the VApp mixin app-theme located here.

So, I think the problem is not linked to storybook, but vuetify instead.

By wrapping the component I wish to test with a v-app, it's ok.

So, for now, please try to add a decorator in your config.js like this :

import { configure, addDecorator } from '@storybook/vue';
import 'vuetify/dist/vuetify.css';

import Vue from 'vue';
import Vuetify from 'vuetify';

Vue.use(Vuetify, {
  theme: {
    // your colors
  },
});

addDecorator(() => ({
  template: '<v-app><story/></v-app>',
}));

...

Sounds ok for you ?

All 23 comments

Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!

same bug here. It accept primary--text class but none of my theme... any ideas ?

i import this in my storybook config

import Vuetify from "vuetify";

import "vuetify/dist/vuetify.min.css";

import theme from "../configs/theme";

import Vue from "vue";

Vue.use(Vuetify, {
  iconfont: "mdi", // 'md' || 'mdi' || 'fa' || 'fa4'
  theme
});

I also am experiencing this

I have the problem too.

After reading vuetify's code, seems the generation of CSS, and injection of the theme is made in the VApp mixin app-theme located here.

So, I think the problem is not linked to storybook, but vuetify instead.

By wrapping the component I wish to test with a v-app, it's ok.

So, for now, please try to add a decorator in your config.js like this :

import { configure, addDecorator } from '@storybook/vue';
import 'vuetify/dist/vuetify.css';

import Vue from 'vue';
import Vuetify from 'vuetify';

Vue.use(Vuetify, {
  theme: {
    // your colors
  },
});

addDecorator(() => ({
  template: '<v-app><story/></v-app>',
}));

...

Sounds ok for you ?

@mdartic that worked for me thanks. What about loading icons?

Don't solve yet :-( I'm gonna search a little more. If I find something, I let you know about it.

I think you just need add <v-app> tag inside Story.

Nice. Thanks for your effort. I feel like maybe I can use Storybook, now.

Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!

does anyone have a up-to-date storybook vuetify boilerplate? I made one a while back but it's very out of date, and I can't seem to get things working again with latest package versions.

I found this : https://github.com/nidkil/vuetify-with-storybook

maybe it can help you ?

I have the problem too.

After reading vuetify's code, seems the generation of CSS, and injection of the theme is made in the VApp mixin app-theme located here.

So, I think the problem is not linked to storybook, but vuetify instead.

By wrapping the component I wish to test with a v-app, it's ok.

So, for now, please try to add a decorator in your config.js like this :

import { configure, addDecorator } from '@storybook/vue';
import 'vuetify/dist/vuetify.css';

import Vue from 'vue';
import Vuetify from 'vuetify';

Vue.use(Vuetify, {
  theme: {
    // your colors
  },
});

addDecorator(() => ({
  template: '<v-app><story/></v-app>',
}));

...

Sounds ok for you ?

The v-app wrapping worked. I wrapped the contents of element to which Vue is mounted.

Hey there, sorry to revive an old issue but I am encountering almost the same issue and couldn't find a solution anywhere.

My app is wrapped with <v-app> and my vuetify options work fine if I build normally (using vue-cli-service build for example).

Vue.use(Vuetify, {
  iconfont: 'fa',
  theme: {
    primary: '#213e79',
    secondary: '#c0d8ed', 
    accent: '#4ea3ed',
    error: '#b71c1c',
    info: '#2196f3',
    success: '#66bb6a', 
    warning: '#f57f17'
  }
});

However, if I build in library mode, these options are NOT taken into account. I'm forced to modify vuetify/dist/vuetify.js for lack of a better solution..

If you guys have any idea what could be the issue or if you have a workaround laying around, that would be great :)

Haven't used it yet, but has anybody tried vuetify-storybook?

https://github.com/vuetifyjs/vue-cli-plugin-vuetify-storybook

@shilman https://github.com/vuetifyjs/vue-cli-plugin-vuetify-storybook with this i cannot use icons and why it's using react in register.js in addon-show-vue-markup

@naveenkash storybook's UI is written in react so that's why it's using react in register.js

The propagated solution does not work anymore. Using:

Storybook 6.0.10
Vuetify 2.2.11

// .storybook/preview.js
import Vue from 'vue'
import 'vuetify/dist/vuetify.css'
import Vuetify from 'vuetify'

Vue.use(Vuetify)

export const decorators = [
  (story) => `<v-app></v-app>`
]

results in [Vue warn]: Error in beforeCreate hook: "Error: Vuetify is not properly initialized

@mrtwinkler for me this works with storybook 6.0.13 and vuetify 2.3.9 with https://storybook.nuxtjs.org/manual-setup/ after
running npx nuxt storybook eject

storybook/preview.js:

import Vuetify from 'vuetify'
import colors from 'vuetify/es5/util/colors'
import 'vuetify/dist/vuetify.min.css'; // all the css for components

const vuetifyConfig = new Vuetify({
  theme: {
    dark: false,
    themes: {
      dark: {
        teal: colors.amber,
        primary: colors.blue.darken2,
        accent: colors.grey.darken3,
        secondary: colors.amber.darken3,
        info: colors.teal.lighten1,
        warning: colors.amber.base,
        error: colors.deepOrange.accent4,
        success: colors.green.accent3
      }
    }
  }
})

export const decorators = [(_) => {
  return {
    vuetify: vuetifyConfig,
    template: `
      <v-app>
        <v-main>
          <v-container fluid>
            <story />
          </v-container>
        </v-main>
      </v-app>`
  }
}]

@Electrofenster You sir deserve a medal. Here is the minimal code I used based on your implemenation. Working with Storybook 6.0.10 and Vuetify 2.2.11:

.storybook/preview.js

import Vue from 'vue'
import Vuetify from 'vuetify'
import 'vuetify/dist/vuetify.css'

Vue.use(Vuetify)

export const decorators = [_ => {
    return {
      vuetify: new Vuetify({}),
      template: `
        <v-app>
          <v-main>
            <v-container fluid>
              <story />
            </v-container>
          </v-main>
        </v-app>`
    }
}]

@mrtwinkler Glad to be able to help you!
After some testing I ran into the issue, that the colors of the buttons changed back to the vuetify defaults when you switch between your stories. To avoid this, just define dark and light and everything should work like a charm.

For example:

const vuetifyConfig = new Vuetify({
  theme: {
    dark: false,
    themes: {
      dark: {
        teal: colors.teal,
        primary: colors.blue.darken2,
        accent: colors.grey.darken3,
        secondary: colors.amber.darken3,
        info: colors.teal.lighten1,
        warning: colors.amber.base,
        error: colors.deepOrange.accent4,
        success: colors.green.accent3
      },
      light: {
        teal: colors.teal,
        primary: colors.blue.darken2,
        accent: colors.grey.darken3,
        secondary: colors.amber.darken3,
        info: colors.teal.lighten1,
        warning: colors.amber.base,
        error: colors.deepOrange.accent4,
        success: colors.green.accent3
      }
    }
  }
})

Thanks again. Will have an eye on that.

Are you guys able to read scss from scoped rules of vuetify?
He it doesn't work, just without the scoped =/
Example:

<style scoped lang="scss">
  .v-input--switch__thumb, .v-input--switch__track{
    background: var(--v-primary-base);
  }
</style>

I have the whole storybook + vuetify + vue cli working perfectly, including scoped css.
I post my setup here for whoever needs some help. My setup include 5 files:

main.js
This is the storybook config file (I set up here webpack options)

const path = require('path')

module.exports = {
  //stories: ['../src/**/*.stories.mdx', '../src/stories/**/*.stories.@(js|jsx|ts|tsx)'],
  stories: ['../stories/**/*.stories.js'],
  addons: ['@storybook/addon-links', '@storybook/addon-essentials'],

  webpackFinal: async (config, { configType }) => {

    config.module.rules = config.module.rules.filter(rule =>
      !rule.test.test('.scss')
    )

    config.module.rules.push({
      test: /\.sass$/,
      use: [
        'style-loader',
        'css-loader', {
          loader: 'sass-loader',
          options: {
            implementation: require('sass'),
            prependData: `@import '@/styles/variables.scss'`,
            sassOptions: {
              fiber: require('fibers'),
              indentedSyntax: true
            }
          }
        }],
    }, {
      test: /\.scss$/,
      use: [
        'style-loader',
        'css-loader', {
          loader: 'sass-loader',
          options: {
            implementation: require('sass'),
            prependData: `@import '@/styles/variables.scss';`,
            sassOptions: {
              fiber: require('fibers'),
            }
          }
        }],
    })

    config.module.rules.push({
      resolve: {
        alias: {
          '@': path.resolve(__dirname, '../src'),
          '~': path.resolve(__dirname, '../src'),
          '~@': path.resolve(__dirname, '../src'),
          stories: path.resolve(__dirname, '../stories'),
          '.storybook': path.resolve(__dirname, '../.storybook'),
          vue: 'vue/dist/vue.js',
          'vue$': 'vue/dist/vue.esm.js',
        }
      }
    })
    return config
  }
}

preview.js
This is the storybook file where I define the vuetify decorator.

import vuetifyConfig from './vuetify_storybook'
require('./vuetify_style.scss')

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
  layout: 'centered',
  backgrounds: {
    default: 'light',
    values: [
      {
        name: 'dark',
        value: '#323539'
      },
      {
        name: 'light',
        value: '#F7F7F7'
      }
    ]
  }
}

export const decorators = [
  () => ({
    vuetify: vuetifyConfig,
    template: `
        <v-app style="background-color: transparent;" class="storybook">
          <v-main>
            <v-container fluid>
              <story />
            </v-container>
          </v-main>
        </v-app>
      `
  })
]

preview-head.html
This is used to import web font from google

<link
  href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700;800;900&display=swap"
  rel="stylesheet"
/>

vuetify_storybook.js
This file contains the vuetify configuration, in order to have the vuetify components, the themes and my icons working in storybook.

import Vue from 'vue'
import * as _Vuetify from 'vuetify/lib'
import themes from '@/plugins/my-themes'
import icons from '@/plugins/my-icons'

const Vuetify = _Vuetify.default

const isVueComponent = obj => obj.name === 'VueComponent'

const VComponents = Object.keys(_Vuetify).reduce((acc, key) => {
  if (isVueComponent(_Vuetify[key])) {
    acc[key] = _Vuetify[key]
  }
  return acc
}, {})

Vue.use(Vuetify, {
  components: {
    ...VComponents
  }
})


export default new Vuetify({
  icons: {
    values: icons
  },
  theme: {
    options: {
      customProperties: true
    },
    themes: themes
  }
})

vuetify_style.scss
This file is used to modify the min-height in v-application, in order to avoid the story canvas to extend to end of the page, but just as big as the component is.

.v-application {
.v-application--wrap {
min-height:0;
}
}

Hope this helps....cheers guys!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wahengchang picture wahengchang  路  3Comments

arunoda picture arunoda  路  3Comments

MrOrz picture MrOrz  路  3Comments

dnlsandiego picture dnlsandiego  路  3Comments

tlrobinson picture tlrobinson  路  3Comments