UNPKG

13.2 kBMarkdownView Raw
1# Storybook Addon Knobs
2
3Storybook Addon Knobs allow you to edit props dynamically using the Storybook UI.
4You can also use Knobs as a dynamic variable inside stories in [Storybook](https://storybook.js.org).
5
6[Framework Support](https://github.com/storybookjs/storybook/blob/master/ADDONS_SUPPORT.md).
7
8This is what Knobs looks like:
9
10[![Storybook Knobs Demo](docs/storybook-knobs-example.png)](https://storybooks-official.netlify.com/?knob-Dollars=12.5&knob-Name=Storyteller&knob-Years%20in%20NY=9&knob-background=%23ffff00&knob-Age=70&knob-Items%5B0%5D=Laptop&knob-Items%5B1%5D=Book&knob-Items%5B2%5D=Whiskey&knob-Other%20Fruit=lime&knob-Birthday=1484870400000&knob-Nice=true&knob-Styles=%7B%22border%22%3A%223px%20solid%20%23ff00ff%22%2C%22padding%22%3A%2210px%22%7D&knob-Fruit=apple&selectedKind=Addons%7CKnobs.withKnobs&selectedStory=tweaks%20static%20values&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybooks%2Fstorybook-addon-knobs)
11
12> Checkout the above [Live Storybook](https://storybooks-official.netlify.com/?knob-Dollars=12.5&knob-Name=Storyteller&knob-Years%20in%20NY=9&knob-background=%23ffff00&knob-Age=70&knob-Items%5B0%5D=Laptop&knob-Items%5B1%5D=Book&knob-Items%5B2%5D=Whiskey&knob-Other%20Fruit=lime&knob-Birthday=1484870400000&knob-Nice=true&knob-Styles=%7B%22border%22%3A%223px%20solid%20%23ff00ff%22%2C%22padding%22%3A%2210px%22%7D&knob-Fruit=apple&selectedKind=Addons%7CKnobs.withKnobs&selectedStory=tweaks%20static%20values&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybooks%2Fstorybook-addon-knobs) or [watch this video](https://www.youtube.com/watch?v=kopW6vzs9dg&feature=youtu.be).
13
14## Getting Started
15
16First of all, you need to install Knobs into your project as a dev dependency.
17
18```sh
19yarn add @storybook/addon-knobs --dev
20```
21
22within `.storybook/main.js`:
23
24```js
25module.exports = {
26 addons: ['@storybook/addon-knobs/register']
27}
28```
29
30Now, write your stories with Knobs.
31
32### With React
33```js
34import React from "react";
35import { withKnobs, text, boolean, number } from "@storybook/addon-knobs";
36
37export default {
38 title: "Storybook Knobs",
39 decorators: [withKnobs]
40};
41// Add the `withKnobs` decorator to add knobs support to your stories.
42// You can also configure `withKnobs` as a global decorator.
43
44// Knobs for React props
45export const withAButton = () => (
46 <button disabled={boolean("Disabled", false)}>
47 {text("Label", "Hello Storybook")}
48 </button>
49);
50
51// Knobs as dynamic variables.
52export const asDynamicVariables = () => {
53 const name = text("Name", "James");
54 const age = number("Age", 35);
55 const content = `I am ${name} and I'm ${age} years old.`;
56
57 return <div>{content}</div>;
58};
59```
60
61### With Vue.js
62MyButton.story.js:
63```js
64import { storiesOf } from '@storybook/vue';
65import { withKnobs, text, boolean } from '@storybook/addon-knobs';
66
67import MyButton from './MyButton.vue';
68
69export default {
70 title: "Storybook Knobs",
71 decorators: [withKnobs]
72};
73
74// Assign `props` to the story's component, calling
75// knob methods within the `default` property of each prop,
76// then pass the story's prop data to the component’s prop in
77// the template with `v-bind:` or by placing the prop within
78// the component’s slot.
79export const exampleWithKnobs = () => ({
80 components: { MyButton },
81 props: {
82 isDisabled: {
83 default: boolean('Disabled', false)
84 },
85 text: {
86 default: text('Text', 'Hello Storybook')
87 }
88 },
89 template: `<MyButton :isDisabled="isDisabled">{{ text }}</MyButton>`
90});
91```
92
93MyButton.vue:
94```vue
95<template>
96 <button :disabled="isDisabled">
97 <slot></slot>
98 </button>
99</template>
100
101<script>
102export default {
103 props: {
104 isDisabled: {
105 type: Boolean,
106 default: false
107 }
108 }
109}
110</script>
111```
112
113### With Angular
114```js
115import { storiesOf } from '@storybook/angular';
116import { boolean, number, text, withKnobs } from '@storybook/addon-knobs';
117
118import { Button } from '@storybook/angular/demo';
119
120export default {
121 title: "Storybook Knobs",
122 decorators: [withKnobs]
123};
124
125export const withKnobs = () => ({
126 component: Button,
127 props: {
128 text: text('text', 'Hello Storybook'), // The first param of the knob function has to be exactly the same as the component input.
129 },
130});
131```
132
133### With Ember
134```js
135import { withKnobs, text, boolean } from '@storybook/addon-knobs';
136import { hbs } from 'ember-cli-htmlbars';
137
138export default {
139 title: 'StoryBook with Knobs',
140 decorators: [withKnobs],
141};
142
143export const button = () => ({
144 template: hbs`
145 <button disabled={{disabled}}>{{label}}</button>
146 `,
147 context: {
148 label: text('label', 'Hello Storybook'),
149 disabled: boolean('disabled', false),
150 },
151});
152```
153
154## Categorization
155
156Categorize your Knobs by assigning them a `groupId`. When a `groupId` exists, tabs will appear in the Knobs storybook panel to filter between the groups. Knobs without a `groupId` are automatically categorized into the `ALL` group.
157
158```js
159export const inGroups = () => {
160 const personalGroupId = 'personal info';
161 const generalGroupId = 'general info';
162
163 const name = text("Name", "James", personalGroupId);
164 const age = number("Age", 35, personalGroupId);
165 const message = text("Hello!", 35, generalGroupId);
166 const content = `
167 I am ${name} and I'm ${age} years old.
168 ${message}
169 `;
170
171 return <div>{content}</div>;
172};
173```
174
175You can see your Knobs in a Storybook panel as shown below.
176
177![](docs/demo.png)
178
179## Available Knobs
180
181These are the Knobs available for you to use. You can import these Knobs from the `@storybook/addon-knobs` module.
182Here's how to import the **text** Knob.
183
184```js
185import { text } from '@storybook/addon-knobs';
186```
187
188Just like that, you can import any other following Knobs:
189
190### text
191
192Allows you to get some text from the user.
193
194```js
195import { text } from '@storybook/addon-knobs';
196
197const label = 'Your Name';
198const defaultValue = 'James';
199const groupId = 'GROUP-ID1';
200
201const value = text(label, defaultValue, groupId);
202```
203
204### boolean
205
206Allows you to get a boolean value from the user.
207
208```js
209import { boolean } from '@storybook/addon-knobs';
210
211const label = 'Agree?';
212const defaultValue = false;
213const groupId = 'GROUP-ID1';
214
215const value = boolean(label, defaultValue, groupId);
216```
217
218### number
219
220Allows you to get a number from the user.
221
222```js
223import { number } from '@storybook/addon-knobs';
224
225const label = 'Age';
226const defaultValue = 78;
227const groupId = 'GROUP-ID1';
228
229const value = number(label, defaultValue);
230```
231
232For use with `groupId`, pass the default `options` as the third argument.
233
234```js
235const value = number(label, defaultValue, {}, groupId);
236```
237
238### number bound by range
239
240Allows you to get a number from the user using a range slider.
241
242```js
243import { number } from '@storybook/addon-knobs';
244
245const label = 'Temperature';
246const defaultValue = 73;
247const options = {
248 range: true,
249 min: 60,
250 max: 90,
251 step: 1,
252};
253const groupId = 'GROUP-ID1';
254
255const value = number(label, defaultValue, options, groupId);
256```
257
258### color
259
260Allows you to get a colour from the user.
261
262```js
263import { color } from '@storybook/addon-knobs';
264
265const label = 'Color';
266const defaultValue = '#ff00ff';
267const groupId = 'GROUP-ID1';
268
269const value = color(label, defaultValue, groupId);
270```
271
272### object
273
274Allows you to get a JSON object or array from the user.
275
276```js
277import { object } from '@storybook/addon-knobs';
278
279const label = 'Styles';
280const defaultValue = {
281 backgroundColor: 'red',
282};
283const groupId = 'GROUP-ID1';
284
285const value = object(label, defaultValue, groupId);
286```
287
288> Make sure to enter valid JSON syntax while editing values inside the knob.
289
290### array
291
292Allows you to get an array of strings from the user.
293
294```js
295import { array } from '@storybook/addon-knobs';
296
297const label = 'Styles';
298const defaultValue = ['Red'];
299const groupId = 'GROUP-ID1';
300
301const value = array(label, defaultValue);
302```
303
304> While editing values inside the knob, you will need to use a separator.
305> By default it is a comma, but this can be overridden by passing a separator variable.
306>
307> ```js
308> import { array } from '@storybook/addon-knobs';
309>
310> const label = 'Styles';
311> const defaultValue = ['Red'];
312> const separator = ':';
313> const value = array(label, defaultValue, separator);
314> ```
315
316For use with `groupId`, pass the default `separator` as the third argument.
317
318```js
319const value = array(label, defaultValue, ',', groupId);
320```
321
322### select
323
324It allows you to get a value from a select box from the user.
325
326```js
327import { select } from '@storybook/addon-knobs';
328
329const label = 'Colors';
330const options = {
331 Red: 'red',
332 Blue: 'blue',
333 Yellow: 'yellow',
334 Rainbow: ['red', 'orange', 'etc'],
335 None: null,
336};
337const defaultValue = 'red';
338const groupId = 'GROUP-ID1';
339
340const value = select(label, options, defaultValue, groupId);
341```
342
343Options can also be an array:
344
345```js
346import { select } from '@storybook/addon-knobs';
347const label = 'Cats';
348const options = ['linus', 'eleanor', 'lover']
349const defaultValue = 'eleanor';
350const groupId = 'GROUP-ID2';
351const value = select(label, options, defaultValue, groupId);
352```
353
354Options can also be an array OF objects:
355
356```js
357const label = 'Dogs';
358const arrayOfObjects = [
359 {
360 label: 'Sparky',
361 dogParent: 'Matthew',
362 location: 'Austin',
363 },
364 {
365 label: 'Juniper',
366 dogParent: 'Joshua',
367 location: 'Austin',
368 },
369];
370const defaultValue = arrayOfObjects[0];
371const groupId = 'GROUP-ID3';
372const value = select(label, options, defaultValue, groupId);
373```
374
375### radio buttons
376
377It allows you to get a value from a list of radio buttons from the user.
378
379```js
380import { radios } from '@storybook/addon-knobs';
381
382const label = 'Fruits';
383const options = {
384 Kiwi: 'kiwi',
385 Guava: 'guava',
386 Watermelon: 'watermelon',
387};
388const defaultValue = 'kiwi';
389const groupId = 'GROUP-ID1';
390
391const value = radios(label, options, defaultValue, groupId);
392```
393
394### options
395
396Configurable UI for selecting a value from a set of options.
397
398```js
399import { optionsKnob as options } from '@storybook/addon-knobs';
400
401const label = 'Fruits';
402const valuesObj = {
403 Kiwi: 'kiwi',
404 Guava: 'guava',
405 Watermelon: 'watermelon',
406};
407const defaultValue = 'kiwi';
408const optionsObj = {
409 display: 'inline-radio'
410};
411const groupId = 'GROUP-ID1';
412
413const value = options(label, valuesObj, defaultValue, optionsObj, groupId);
414```
415> The display property for `optionsObj` accepts:
416> - `radio`
417> - `inline-radio`
418> - `check`
419> - `inline-check`
420> - `select`
421> - `multi-select`
422
423### files
424
425It allows you to get a value from a file input from the user.
426
427```js
428import { files } from '@storybook/addon-knobs';
429
430const label = 'Images';
431const accept = '.xlsx, .pdf';
432const defaultValue = [];
433const groupId = 'GROUP-ID1';
434
435const value = files(label, accept, defaultValue, groupId);
436```
437
438> You can optionally specify a [list of file types](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept) which the file input should accept.
439> Multiple files can be selected, and will be returned as an array of [Data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs).
440
441### date
442
443Allows you to get date (and time) from the user.
444
445```js
446import { date } from '@storybook/addon-knobs';
447
448const label = 'Event Date';
449const defaultValue = new Date('Jan 20 2017');
450const groupId = 'GROUP-ID1';
451
452const value = date(label, defaultValue, groupId);
453```
454
455> Note: the default value must not change - e.g., do not do `date('Label', new Date())` or `date('Label')`.
456
457The `date` knob returns the selected date as stringified Unix timestamp (e.g. `"1510913096516"`).
458If your component needs the date in a different form you can wrap the `date` function:
459
460```js
461function myDateKnob(name, defaultValue) {
462 const stringTimestamp = date(name, defaultValue)
463 return new Date(stringTimestamp)
464}
465```
466
467### button
468
469It allows you to include a button and associated handler.
470
471```js
472import { button } from '@storybook/addon-knobs';
473
474const label = 'Do Something';
475const handler = () => doSomething('foobar');
476const groupId = 'GROUP-ID1';
477
478button(label, handler, groupId);
479```
480
481Button knobs cause the story to re-render after the handler fires.
482You can prevent this by having the handler return `false`.
483
484### withKnobs options
485
486withKnobs also accepts two optional options as story parameters.
487Usage:
488
489```js
490import { withKnobs } from '@storybook/addon-knobs';
491
492export default {
493 title: 'Storybook Knobs',
494 decorators: [withKnobs],
495};
496
497export const defaultView = () => (
498 <div />
499);
500defaultView.story = {
501 parameters: {
502 knobs: {
503 // Doesn't emit events while user is typing.
504 timestamps: true,
505
506 // Escapes strings to be safe for inserting as innerHTML. This option is true by default. It's safe to set it to `false` with frameworks like React which do escaping on their side.
507 // You can still set it to false, but it's strongly discouraged to set to true in cases when you host your storybook on some route of your main site or web app.
508 escapeHTML: true,
509 }
510 }
511};
512```
513
514## Typescript
515
516If you are using Typescript, make sure you have the type definitions installed for the following libs:
517
518- node
519- react
520
521You can install them using: (*assuming you are using Typescript >2.0.*)
522
523```sh
524yarn add @types/node @types/react --dev
525```
526