I have a question regarding Storybook and Vue components with v-models. When writing a story for let's say an input component with a v-model i want a control reflecting the value of this v-model. Setting the modelValue from the control is no problem, but when using the component itself the control value stays the same. I am searching the web for a while now but i can't seem to find a solution for this.
A small example:
// InputComponent.vue
<template>
<input
type="text"
:value="modelValue"
@input="updateValue"
:class="`form-control${readonly ? '-plaintext' : ''}`"
:readonly="readonly"
/>
</template>
<script lang="ts">
export default {
name: "GcInputText"
}
</script>
<script lang="ts" setup>
defineProps({
modelValue: {
type: String,
default: null
},
readonly: {
type: Boolean,
default: false
}
});
const emit = defineEmits(['update:modelValue']);
const updateValue = (event: Event) => {
const target = event.target as HTMLInputElement;
emit('update:modelValue', target.value);
}
</script>
In Storybook:
Does anyone have a solution to make this working?
Thanks in advance!
In my case, I have a custom select input that uses a modelValue
prop.
I tried this and worked for me:
at my-component.stories.js:
import { ref } from 'vue'
import MyComponent from './MyComponent.vue'
export default {
title: 'Core/MyComponent',
component: MyComponent,
argTypes: { }
}
const Template = (args) => ({
components: { MyComponent },
setup() {
let model = ref('Javascript')
const updateModel = (event) => model.value = event
return { args, model, updateModel }
},
template: '<my-component v-bind="args" :modelValue="model" @update:modelValue="updateModel" />'
})
export const Default = Template.bind({})
Default.args = {
options: [
'Javascript',
'PHP',
'Java'
]
}
You can also use v-model directly:
import type { Meta, StoryObj } from '@storybook/vue3';
import { ref, watch } from 'vue'
import MyComponent from './MyComponent.vue'
export default {
title: 'Core/MyComponent',
component: MyComponent,
} satisfies Meta<typeof MyComponent>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Example: Story = {
render: (args) => ({
components: { MyComponent },
setup() {
const model = ref(args.modelValue);
// Optional: Keeps v-model in sync with storybook args
watch(
() => args.modelValue,
(val) => {
model.value = val;
},
);
return { args, model };
},
template: '<MyComponent v-bind="args" v-model="model" />',
}),
args: {
modelValue: 'Value',
},
};
I am using Storybook version 8.1.1 in this solution. You could probably also keep the v-model value in sync by using writable computed property, but watcher works too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With