UNPKG

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