storybook: addon-knobs not working with vue from v4.0.8

Upgraded from 4.0.4 to 4.0.12 and knobs were no longer visible or working. Tested each version and 4.0.7 works but 4.0.8 does not. I assume it’s something to do with #4773.

Typical use of knobs looks something like this (if that helps):

template: '<simple-knob-example :age="age" />',
data: () => ({
  age: 40,
}),

I don’t see any error messages or anything, but if there is anything else I can do to help please let us know.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 16
  • Comments: 50 (15 by maintainers)

Commits related to this issue

Most upvoted comments

Having the same issue as above.

Knobs don’t work with any version above 4.0.2, tried with 4.0.7 and that didn’t work for me either.

Remove All Global Decorators

I was only able to get it working by removing all global decorators including withKnobs. And only adding the knobs decorator to the story itself.

storiesOf('MyComponent', module)
  .addDecorator(withKnobs)
  .add('Simple', () => ({
    props: {
      name: {
        type: String,
        default: text('Name', 'John Doe'),
      },
    },
    template: `<div>I am {{ name }}</div>`,
  }))

Make sure your config.js doesn’t include any global decorators

I’m confused. Several comments in this thread seem to suggest that this is an intended change, and that Vue stories should be updated to move knobs onto the props object. But #4773 doesn’t mention any breaking changes like this - to the contrary it seems to say that putting knobs in the template should still work (though it may cause stories to get destroyed and recreated every time a knob value updates).

Could @y-nk or @igor-dv clarify what’s happening here - is this just a bug, or do all Vue knobs stories need to be ported to the new behavior?

Upgraded from 3.4.0 to 4.0.12 and came across the same issue. I can get the knobs to show up with my 3.4.0 config (in my case they’re added globally in .storybook/config.js), but changing the value of a knob doesn’t update the component’s props.

You can even see it being broken on the official Vue storybook example.

It looks like @y-nk’s update in #4773 breaks the template string injection approach. As in, something like this no longer works:

  .add('All knobs', () => {
    const name = text('Name', 'Jane');
    const stock = number('Stock', 20, {
      range: true,
      min: 0,
      max: 30,
      step: 5,
    });
    const fruits = {
      Apple: 'apples',
      Banana: 'bananas',
      Cherry: 'cherries',
    };
    const fruit = select('Fruit', fruits, 'apples');
    const price = number('Price', 2.25);

    const colour = color('Border', 'deeppink');
    const today = date('Today', new Date('Jan 20 2017 GMT+0'));
    const items = array('Items', ['Laptop', 'Book', 'Whiskey']);
    const nice = boolean('Nice', true);

    const stockMessage = stock
      ? `I have a stock of ${stock} ${fruit}, costing &dollar;${price} each.`
      : `I'm out of ${fruit}${nice ? ', Sorry!' : '.'}`;
    const salutation = nice ? 'Nice to meet you!' : 'Leave me alone!';
    const dateOptions = { year: 'numeric', month: 'long', day: 'numeric', timeZone: 'UTC' };

    button('Arbitrary action', action('You clicked it!'));

    return {
      template: `
          <div style="border:2px dotted ${colour}; padding: 8px 22px; border-radius: 8px">
            <h1>My name is ${name},</h1>
            <h3>today is ${new Date(today).toLocaleDateString('en-US', dateOptions)}</h3>
            <p>${stockMessage}</p>
            <p>Also, I have:</p>
            <ul>
              ${items.map(item => `<li key=${item}>${item}</li>`).join('')}
            </ul>
            <p>${salutation}</p>
          </div>
        `,
    };
  })

@y-nk, I understand that the story I linked to was a false-positive, but to have it up as an example that outright doesn’t work anymore is very confusing. We’re essentially supposed to map knobs to the story’s props via the default value of the prop, and then use the props in the template string. I’m all for that, because template string injection always felt too hacky to me.

However, I have the same issue as @Laslo89, where I’ve defined a global decorator (in my case, it applies some global styling to make storybook consistent with the main web app) that breaks addon-knobs. Commenting out my global decorator fixes knob propagation to props. Is there any open issue I can track that fixes this global decorator issue with the latest addon-knobs?

I’ll work on a PR that updates the addon-knobs example for vue-kitchen-sink in the meantime.

Hey @Jack-Barry,

I’m a little confused as to why you’re passing an enabled prop to MyButton when your prop is called initialEnabled.

Does this work for you?

import { storiesOf, Story } from '@storybook/vue'
import { withKnobs, text, boolean } from '@storybook/addon-knobs'

import MyButton from './MyButton.vue'

const stories: Story = storiesOf('MyButton', module)

stories.addDecorator(<any>withKnobs)

stories.add('Default', () => ({
  components: { MyButton },
  props: {
    buttonText: {
      default: text('buttonText', 'Click Me NOW')
    },
    initialEnabled: {
      default: boolean('initialEnabled', true)
    }
  },
  template: `<my-button :button-text="buttonText" :initial-enabled="initialEnabled"></my-button>`
}))

I don’t agree with the props approach at all. Why would you need to specify props again if they are already specified in a component it self? It brings additional not needed complexity to the stories.

Before upgrade my solution that worked was like this:

.add('Choice with knobs', () => {
    return {
      components: { Choice },
      data() {
        return {
          value: boolean('Value', false),
          disabled: boolean('Disabled', false),
          text: text('Text', 'Are you awesome?')
        };
      },
      template: `
                  <Choice 
                    :text="text" 
                    :disabled="disabled" 
                    :value.sync="value" 
                  />`,
      methods: {}
    };
  });

It’s clean, simple and story can be directly copied from storybook for reuse.

Edit: knobs in templates do not work anymore, but this was also the case before my clean up PR

So I feel a little confused now 🤔, are you saying knobs are no longer supported with vue? They definitely worked in v4.0.7 but don’t in v4.0.8.

Reading above it sounds like props are preferred over data, so I’ve tried to use props instead of data and the knobs show in storybook which is an improvement, but changing the values does not update the component 😦

Does anyone have a working example on how to get knobs working with vue in v4.0.8 or later?

@HerrBertling After removing addon-centered it rerenders. Thanks for the hint!

UPDATE: THE NEW EXPORT SYNTAX MAKES KNOBS WORK.

Did some additional testing now:

It did stop working since after 5.1.9, because I tested 5.2.0 just now and it doesn’t work.

EDIT: HOWEVER, I just found out that 5.2.1 works perfectly fine with the new export syntax, I just didn’t realize it because I had made a mistake in my component. So basically, you broke support for knobs in the old syntax, but the new one is working fine…

This is the story I used, which IS WORKING with 5.2.1. Much more simplified this time around (with defaults from the sb cli basically), but the downside is that the old syntax is not supported for knobs anymore…

import { withKnobs, number } from '@storybook/addon-knobs'
import { addDecorator } from '@storybook/vue'
import { linkTo } from '@storybook/addon-links'

import HelloWorld from '../src/components/HelloWorld'

export default {
    title: 'HelloWorld',
}

addDecorator(withKnobs)

export const toStorybook = () => ({
    components: { HelloWorld },
    props: {
        initialFloors: {
            type: Number,
            default: () => number('initialFloors', 0),
        },
    },
    template: '<HelloWorld v-bind="$props" />',
    methods: { action: linkTo('Button') },
})

toStorybook.story = {
    name: 'to Storybook',
}

Your idea of what Storybook and addon-knobs does is correct. However, I think you’re confused about how props and state work in Vue, which is irrelevant to Storybook and this issue.

Consider only setting enabled as a prop, instead of deriving state from it (which is generally an anti-pattern), and look into the pattern of controlled vs uncontrolled components. You’re mixing the two here, which can be done, but I think your implementation is a bit off.

Hopefully that helps, I’m trying to stay on-topic!

FYI: For me, the props way worked after removing the only other addon I had globally registered in my config.js 🥁

it was addon-centered 🤷‍♂️

So a wild guess without looking further into it (and having no idea of how storybook addon registration works): Something seems to break when registering other addons globally? 🤔

EDIT: Apparently, I’m not the only one having discovered this 😃 https://github.com/storybooks/storybook/issues/5211

The example from https://github.com/storybooks/storybook/issues/4947#issuecomment-448001928 should work. Also you should try the 4.2 alpha which contains https://github.com/storybooks/storybook/pull/5057 and fixes a lot of problems with knobs and vue