{"id":28336,"date":"2022-03-23T22:58:25","date_gmt":"2022-03-23T22:58:25","guid":{"rendered":"http:\/\/Making-Better-Components-With-Storybook"},"modified":"2022-03-23T22:58:25","modified_gmt":"2022-03-23T22:58:25","slug":"making-better-components-with-storybook","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/","title":{"rendered":"Making Better Components With Storybook"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>When you\u2019re working on large projects, it can help to have reusable components to handle the same functionality across different views. This saves time on writing code, makes it easier to maintain apps with many views, and can even lead to components that are usable in different projects.<\/p>\n<p>There are a few different ways to do this and we\u2019ll be taking a look at component-driven development and one of the tools you can use to help with that.<\/p>\n<h2>Quick background on component-driven development<\/h2>\n<p>Component-driven development is when you create independent components. So your components aren\u2019t tied to any particular data, APIs, or other functionality. They can stand alone on their own and you work with them however you need at the time.<\/p>\n<p>Some common components you\u2019ll see created like this include dropdowns, buttons, and containers. Building your components independently of each other can help you model your system better because you can drop in the pieces you need.<\/p>\n<p>You\u2019ll even be able to write better tests for your apps because you can test components with more simple mock data. It also makes it clearer to find issues since you can test everything in isolation.<\/p>\n<h2>Where Storybook comes in<\/h2>\n<p>This is where a tool like <a href=\"https:\/\/storybook.js.org\/\">Storybook<\/a> comes in. It lets you develop your components in isolation from the rest of the app. That means you can test components without connecting to a server or running all of the functionality in the app.<\/p>\n<p>Storybook starts up its own process to let you interact with components and demonstrate how components should work. Something else it helps with is the documentation for your apps.<\/p>\n<p>You\u2019ll be able to add descriptions for props that are passed to components, explain how the component changes under different conditions, and check for accessibility issues.<\/p>\n<h2>Generating a Redwood app<\/h2>\n<p>Now that you know a bit about component-driven development and Storybook, let\u2019s see how it actually works. We\u2019ll do this with a new Redwood app since it comes with Storybook integration by default.<\/p>\n<p>You can make a new app by running the following command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn create redwood-app storybook-component\n<\/code><\/span><\/pre>\n<p>This will make a new Redwood project with several files and directories generated for us. While our focus will be in the <code>web<\/code> directory, it\u2019s good to note that the <code>api<\/code> directory is where your database connection and GraphQL server will live.<\/p>\n<h3>A new page<\/h3>\n<p>The front-end is where we\u2019ll be focused, so let\u2019s start by adding a new page to the app. Run the following command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn rw g page display \/\n<\/code><\/span><\/pre>\n<p>This creates a new page called <code>DisplayPage<\/code> in the <code>web &gt; src &gt; pages<\/code> directory. We\u2019ll use this page to display a video to the user, kind of like if they went to a page on YouTube.<\/p>\n<p>Before we add the video component, let\u2019s take a look at what we have in Storybook just from our Redwood commands. So we\u2019ll start up Storybook with:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn rw storybook\n<\/code><\/span><\/pre>\n<p>This should start up Storybook and you should see something like this in the browser.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1628209526\/e-603fc55d218a650069f5228b\/j18xgurxczkffvigncoi.png\" alt=\"display page component in Storybook\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1006\"\/><\/p>\n<p>If you look in <code>web &gt; src &gt; pages &gt; DisplayPage<\/code>, you\u2019ll see the <code>DisplayPage.stories.js<\/code> file. This is the type of file Storybook will be looking for to render individual components. The Storybook page will render the <code>DisplayPage<\/code> component exactly like it\u2019s written. Here\u2019s what the story page should look like.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> DisplayPage <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/DisplayPage'<\/span>\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> generated = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">DisplayPage<\/span> \/&gt;<\/span><\/span>\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> { <span class=\"hljs-attr\">title<\/span>: <span class=\"hljs-string\">'Pages\/DisplayPage'<\/span> }\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>A couple of things to note for the <code>stories.js<\/code> file.<\/p>\n<ul>\n<li>The name of the exported component is <code>generated<\/code> and that\u2019s the title of this particular view in the story. This name could be anything else you see fit. We\u2019ll go into more detail on story views in just a bit.<\/li>\n<li>The <code>title<\/code> that\u2019s part of the export is how components and different views are grouped in Storybook. The directory format defines the group name and the component name for the tab in that group.<\/li>\n<\/ul>\n<p>Redwood generates this basic file by default so all we have to do is update it.<\/p>\n<p>To get a better feel for writing stories, let\u2019s make a component for the video that gets shown to the user.<\/p>\n<h3>Making a new component<\/h3>\n<p>We\u2019ll run the following command to create the video component:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn rw g component video\n<\/code><\/span><\/pre>\n<p>This command will create three new files in the <code>web &gt; src &gt; component<\/code> directory. We have the <code>Video.js<\/code> file that holds the actual video component. Then there\u2019s the <code>Video.stories.js<\/code> file that holds the Storybook story. Lastly, there\u2019s the <code>Video.test.js<\/code> file that holds the tests for this component.<\/p>\n<p>Let\u2019s modify the existing code to render a video element with several props that are passed in. So in <code>web &gt; src &gt; component &gt; Video.js<\/code>, you can delete the existing code and paste the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> Video = <span class=\"hljs-function\">(<span class=\"hljs-params\">{ videoSrc, width, height, controls }<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">video<\/span> <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">{width}<\/span> <span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">{height}<\/span> <span class=\"hljs-attr\">controls<\/span>=<span class=\"hljs-string\">{controls}<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">source<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{videoSrc}<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"video\/mp4\"<\/span> \/&gt;<\/span>\n      Your browser does not support the video tag.\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">video<\/span>&gt;<\/span><\/span>\n  )\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Video\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This is where the beauty of Storybook comes in. We\u2019re not going to worry about adding this component to the <code>DisplayPage<\/code> while we\u2019re developing it. We\u2019re going to use the story page to test and document how the <code>Video<\/code> component works.<\/p>\n<h2>Updating the story<\/h2>\n<p>Since we have the <code>Video<\/code> component ready to play with, we can switch over to the <code>Video.stories.js<\/code> file and start writing new pieces to the story.<\/p>\n<p>The first thing we\u2019ll do is update the <code>generated<\/code> view. We\u2019ll rename it to <code>index<\/code> because it will act as the starting point for working with the <code>Video<\/code> component and it\u2019ll have more documentation than the other views we\u2019ll add.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> index = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>There are several props used in this component.<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        width: sets the width of the video component\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        height: sets the height of the video component\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        videoSrc: sets the width of the video component\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        controls: sets whether the video controls are shown or not\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Video<\/span> <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">\"320\"<\/span> <span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">\"240\"<\/span> <span class=\"hljs-attr\">videoSrc<\/span>=<span class=\"hljs-string\">\"https:\/\/res.cloudinary.com\/milecia\/video\/upload\/v1606580790\/elephant_herd.mp4\"<\/span> <span class=\"hljs-attr\">controls<\/span>=<span class=\"hljs-string\">{true}<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/&gt;<\/span><\/span>\n  )\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here, we\u2019ve defined the props that are passed into the <code>Video<\/code> component and we have an example of the component in use. If you check back in the browser, you should see something like this.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1628211472\/e-603fc55d218a650069f5228b\/vqrdqgitw39odc5kqfxt.png\" alt=\"video component in Storybook\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1012\"\/><\/p>\n<p>Many times you\u2019ll have different use cases for the same component and Storybook can help you look at those individually as well. To handle passing props to different use case views, we have to introduce <code>args<\/code> into our story. We\u2019ll do that by adding the following template in <code>Video.stories.js<\/code>.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> Template = <span class=\"hljs-function\"><span class=\"hljs-params\">args<\/span> =&gt;<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Video<\/span> {<span class=\"hljs-attr\">...args<\/span>} \/&gt;<\/span><\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This will let us pass different props to the <code>Video<\/code> component for each view we make. We\u2019ll make a default view, a large view, and a view with no controls. Add the following code below the <code>index<\/code> view we made earlier.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> Default = Template.bind({})\nDefault.args = {\n  <span class=\"hljs-attr\">controls<\/span>: <span class=\"hljs-literal\">true<\/span>,\n  <span class=\"hljs-attr\">height<\/span>: <span class=\"hljs-string\">\"240\"<\/span>,\n  <span class=\"hljs-attr\">width<\/span>: <span class=\"hljs-string\">\"320\"<\/span>,\n  <span class=\"hljs-attr\">videoSrc<\/span>: <span class=\"hljs-string\">\"https:\/\/res.cloudinary.com\/milecia\/video\/upload\/v1606580790\/elephant_herd.mp4\"<\/span>\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> Large = Template.bind({})\nLarge.args = {\n  <span class=\"hljs-attr\">controls<\/span>: <span class=\"hljs-literal\">true<\/span>,\n  <span class=\"hljs-attr\">height<\/span>: <span class=\"hljs-string\">\"840\"<\/span>,\n  <span class=\"hljs-attr\">width<\/span>: <span class=\"hljs-string\">\"1020\"<\/span>,\n  <span class=\"hljs-attr\">videoSrc<\/span>: <span class=\"hljs-string\">\"https:\/\/res.cloudinary.com\/milecia\/video\/upload\/v1606580788\/sea-turtle.mp4\"<\/span>\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> NoControls = Template.bind({})\nNoControls.args = {\n  <span class=\"hljs-attr\">controls<\/span>: <span class=\"hljs-literal\">false<\/span>,\n  <span class=\"hljs-attr\">height<\/span>: <span class=\"hljs-string\">\"560\"<\/span>,\n  <span class=\"hljs-attr\">width<\/span>: <span class=\"hljs-string\">\"840\"<\/span>,\n  <span class=\"hljs-attr\">videoSrc<\/span>: <span class=\"hljs-string\">\"https:\/\/res.cloudinary.com\/milecia\/video\/upload\/v1606580790\/elephant_herd.mp4\"<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We\u2019re using Cloudinary to store the videos and getting a URL to use as the source for the <code>Video<\/code> component to keep things simple. You can <a href=\"https:\/\/cloudinary.com\/users\/register\/free\">set up a free account<\/a> and upload your own videos if you want to see something more interesting.<\/p>\n<p>We\u2019re binding the view to the <code>Template<\/code> we created and that\u2019s how we\u2019re able to see them in the browser. You should see something like this now.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1628212801\/e-603fc55d218a650069f5228b\/szzo4ojxez5dpb2jen6p.png\" alt=\"all of the video component views in Storybook\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1000\"\/><\/p>\n<h2>Finished code<\/h2>\n<p>You can take a look at the stories for the <code>Video<\/code> and <code>DisplayPage<\/code> components in <a href=\"https:\/\/codesandbox.io\/s\/jovial-gates-g9k59\">this Code Sandbox<\/a> or you can clone the whole project from <a href=\"https:\/\/github.com\/flippedcoder\/blog-examples\/tree\/main\/storybook-component\">the <code>storybook-component<\/code> directory in this repo<\/a>.<\/p>\n<\/div>\n  \n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/jovial-gates-g9k59?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"jovial-gates-g9k59\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n  <div class=\"wp-block-cloudinary-markdown \"><h2>Conclusion<\/h2>\n<p>Developing components in isolation from the complete app can make it easier to catch bugs before they become issues and it can help give developers a better understanding of how the whole system works.<\/p>\n<p>Configuring Storybook in an existing project doesn\u2019t require much time, but it\u2019s a nice integration that already comes with Redwood. Whether you\u2019re working with multiple projects that depend on the same set of components or you\u2019re working with one large app that has a lot of components, using Storybook can help you with long-term maintenance and onboarding new engineers.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28337,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,177,246,371,303],"class_list":["post-28336","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-javascript","tag-react","tag-under-review","tag-video"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Making Better Components With Storybook<\/title>\n<meta name=\"description\" content=\"When you&#039;re building components to use in an app, it helps to work with them in isolation. With Storybook, you can test and create components in isolation from the entire app. In this tutorial, we&#039;ll go over writing stories for components in Redwood.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Making Better Components With Storybook\" \/>\n<meta property=\"og:description\" content=\"When you&#039;re building components to use in an app, it helps to work with them in isolation. With Storybook, you can test and create components in isolation from the entire app. In this tutorial, we&#039;ll go over writing stories for components in Redwood.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-03-23T22:58:25+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924782\/Web_Assets\/blog\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"3984\" \/>\n\t<meta property=\"og:image:height\" content=\"2656\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Making Better Components With Storybook\",\"datePublished\":\"2022-03-23T22:58:25+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/\"},\"wordCount\":5,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924782\/Web_Assets\/blog\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815.jpg?_i=AA\",\"keywords\":[\"Guest Post\",\"Javascript\",\"React\",\"Under Review\",\"Video\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/\",\"name\":\"Making Better Components With Storybook\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924782\/Web_Assets\/blog\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815.jpg?_i=AA\",\"datePublished\":\"2022-03-23T22:58:25+00:00\",\"description\":\"When you're building components to use in an app, it helps to work with them in isolation. With Storybook, you can test and create components in isolation from the entire app. In this tutorial, we'll go over writing stories for components in Redwood.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924782\/Web_Assets\/blog\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924782\/Web_Assets\/blog\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815.jpg?_i=AA\",\"width\":3984,\"height\":2656},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Making Better Components With Storybook\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Making Better Components With Storybook","description":"When you're building components to use in an app, it helps to work with them in isolation. With Storybook, you can test and create components in isolation from the entire app. In this tutorial, we'll go over writing stories for components in Redwood.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/","og_locale":"en_US","og_type":"article","og_title":"Making Better Components With Storybook","og_description":"When you're building components to use in an app, it helps to work with them in isolation. With Storybook, you can test and create components in isolation from the entire app. In this tutorial, we'll go over writing stories for components in Redwood.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-03-23T22:58:25+00:00","og_image":[{"width":3984,"height":2656,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924782\/Web_Assets\/blog\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815.jpg?_i=AA","type":"image\/jpeg"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/"},"author":{"name":"","@id":""},"headline":"Making Better Components With Storybook","datePublished":"2022-03-23T22:58:25+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/"},"wordCount":5,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924782\/Web_Assets\/blog\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815.jpg?_i=AA","keywords":["Guest Post","Javascript","React","Under Review","Video"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/","name":"Making Better Components With Storybook","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924782\/Web_Assets\/blog\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815.jpg?_i=AA","datePublished":"2022-03-23T22:58:25+00:00","description":"When you're building components to use in an app, it helps to work with them in isolation. With Storybook, you can test and create components in isolation from the entire app. In this tutorial, we'll go over writing stories for components in Redwood.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924782\/Web_Assets\/blog\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924782\/Web_Assets\/blog\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815.jpg?_i=AA","width":3984,"height":2656},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Making Better Components With Storybook"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"parsely":{"version":"1.1.0","canonical_url":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/","smart_links":{"inbound":0,"outbound":0},"traffic_boost_suggestions_count":0,"meta":{"@context":"https:\/\/schema.org","@type":"NewsArticle","headline":"Making Better Components With Storybook","url":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/","mainEntityOfPage":{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924782\/Web_Assets\/blog\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815.jpg?_i=AA&w=150&h=150&crop=1","image":{"@type":"ImageObject","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924782\/Web_Assets\/blog\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815.jpg?_i=AA"},"articleSection":"Uncategorized","author":[],"creator":[],"publisher":{"@type":"Organization","name":"Cloudinary Blog","logo":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA"},"keywords":["guest post","javascript","react","under review","video"],"dateCreated":"2022-03-23T22:58:25Z","datePublished":"2022-03-23T22:58:25Z","dateModified":"2022-03-23T22:58:25Z"},"rendered":"<meta name=\"parsely-title\" content=\"Making Better Components With Storybook\" \/>\n<meta name=\"parsely-link\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/making-better-components-with-storybook\/\" \/>\n<meta name=\"parsely-type\" content=\"post\" \/>\n<meta name=\"parsely-image-url\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924782\/Web_Assets\/blog\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815.jpg?_i=AA&w=150&amp;h=150&amp;crop=1\" \/>\n<meta name=\"parsely-pub-date\" content=\"2022-03-23T22:58:25Z\" \/>\n<meta name=\"parsely-section\" content=\"Uncategorized\" \/>\n<meta name=\"parsely-tags\" content=\"guest post,javascript,react,under review,video\" \/>","tracker_url":"https:\/\/cdn.parsely.com\/keys\/cloudinary.com\/p.js"},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924782\/Web_Assets\/blog\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815\/4c0c0ca07d80ba55ca3ae529da78eed275b83e7c-3984x2656-1_2833718815.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28336","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=28336"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28336\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28337"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28336"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28336"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28336"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}