Today I learned about Storybooks decorators and used them for documenting validation errors on inputs.
Decorators are Storybooks way to wrap a story into some extra HTML.
By that, a basic component can for example be documented in a better visual way, as suggested by Storybooks, by adding some space around a story.
Writing an input component
Now to my use-case: I was developing input components with Vue, while writing the related stories.
Besides showing the default state of an input, I alse wanted to show the invalid state.
As an example I'd have a component called InputText.vue in which I would simply pass down all the props and attrs to the input field.
<template>
<div class="input-group">
<label v-if="label" :for="id">{{ label }}</label>
<input type="text" v-bind="{...$props, ...$attrs}" />
</div>
</template>
...
<style>
...
input:invalid {
border-color: red;
}
</style>
With an InputText.stories.js as follows:
export default {
title: "Forms/Inputs/Text",
component: InputText,
decorators: [],
};
const Template = (args) => ({
props: Object.keys(args),
components: { InputText },
template: '<InputText v-bind="$props" />',
});
export const EmptyRequired = Template.bind({});
EmptyRequired.story = {
name: "Required field",
args: {
id: "field1",
label: "Some Label",
required: true,
},
};
So the required
attribute would end up at the components input tag, making it invalid with an empty value.
Per default the invalid state would never be shown in Storybook.
Sure, I could've added an extra class to my CSS, which probably wouldn't ever be used in the final application, so I wanted to avoid that.
Adding a decorator
Instead I used a decorator to wrap my story into a form
tag with:
decorators: [() => ({ template: "<form><story /></form>" })],
By that I could make use of the browser built-in validation and have my possible validation states show up right away when setting the attribute required and no value.
This of course works not only with the required
attribute, but also with something like an invalid e-mail address on type="email"
inputs.
Top comments (0)