How to share your TwigComponent with your team ?
Published: 2024-05-15 20:40:21

## **Quick Reminders**

This article follows my previous one. If you haven't read it yet, you can do so here: [Symfony Can Help You Fall in Love with Your Front-End Team](https://dev.to/sensiolabs/symfony-can-help-you-fall-in-love-with-your-front-end-team-4dak).

To give you context, we are developing a small application that lets you listen to various live radio stations.


![Our projects](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/que827sw262nye4bgxmy.png)

We've adopted the principles from [Component Architecture](https://dev.to/webmamba/how-to-integrate-component-architecture-into-symfony-4bjb) and, naturally, after designing various components of differing sizes and complexity, we are beginning to establish what is known as a design system.

## **Overwhelmed by All These Components?**

It's common to feel overwhelmed as the number of components grows. In a team setting, or when developing new features, it's crucial to know what components are already available. When we create a new component, we want to share it immediately with our teammates.

So, how do we manage this?

Documenting everything? Yes, but it's time-consuming, and let's face it, we're developers—we tend to be a bit lazy.

But here’s some good news: there’s already a solution in the JavaScript world called [Storybook](https://storybook.js.org/)!

## **What is Storybook?**

Storybook is an exceptional tool for documenting components. It's specifically designed for this purpose, but it offers much more. It allows us to build components in isolation, test them, and mock them to see how they appear in different states or create specific end-to-end scenarios for each component, among many other features! And if you're still not convinced, just look at how beautiful your documentation can look with Storybook:


![Storybook exemple](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t5n9bjwm4keecs1xo8he.png)

Here you can see an example of how I documented our Alert component. This documentation helps my teammates understand how to use the component and the different variations available.

## **Integrating Storybook with Symfony**

Thanks to contributions from the community, you can now use the StorybookBundle for Symfony, developed by my friend [Nicolas](https://github.com/squrious) (not Grekas). I’m very excited about this release—not only because it involved a lot of work, but also because this bundle demonstrates that Symfony can match any front-end framework in capabilities.

To get started, install the bundle with Composer:

```bash
**composer require sensiolabs/storybook-bundle**
```

Then you can use the init command to configure everything for you.

```bash
bin/console storybook:init
```

Don’t run away! We gonna use npm but just to run the storybook. This will not have any impact to your project. And the bundle have an integration with AssetMapper, npm is just to start the storybook.

```bash
npm install
```

And to finish

```bash
npm run storybook
```

And just like that you are fully set up! You can go to: http://localhost:6006/ (it can be something else if your port is not available) to admire your storybook.

## Write your first story

Let's get started! The first thing we want to do is show our Alert component in our Storybook.

```jsx
import Alert from '../templates/components/Alert.html.twig';
import { twig } from '@sensiolabs/storybook-symfony-webpack5';

export default {
  component: (args) => ({
    components: {Alert},
    template: twig`
      <twig:Alert color="{{ color }}" size="{{ size }}" position="{{ position }}">
        {{ message }}
      </twig:Alert>
  `
  }),
  argTypes: {
    color: {
      options: ['blue', 'red', 'green'],
      control: {type: 'radio'},
    },
    size: {
      options: ['lg', 'md', 'sm'],
      control: {type: 'radio'},
    },
    position: {
      options: ['top-left', 'top-right', 'bottom-left', 'bottom-right'],
      control: {type: 'radio'},
    }
  }
}

export const Default = {
  args: {
    color: 'blue',
    size: 'sm',
    position: 'top-left',
    message: 'Hello world!'
  },
}
```

Let me explain what we have here:

```jsx
import Alert from '../templates/components/Alert.html.twig';
```

We import our component template. Yes, this is Twig code, but thanks to the bundle, it works!

```jsx
import { twig } from '@sensiolabs/storybook-symfony-webpack5';
```

Then we import a **`twig`** function that allows us to write Twig code directly in our JavaScript.

```jsx
export default {
  component: (args) => ({
    components: {Alert},
    template: twig`
      <twig:Alert color="{{ color }}" size="{{ size }}" position="{{ position }}">
        {{ message }}
      </twig:Alert>
  `
  }),
  argTypes: {
    color: {
      options: ['blue', 'red', 'green'],
      control: {type: 'radio'},
    },
    size: {
      options: ['lg', 'md', 'sm'],
      control: {type: 'radio'},
    },
    position: {
      options: ['top-left', 'top-right', 'bottom-left', 'bottom-right'],
      control: {type: 'radio'},
    }
  }
}
```

Here is everything that is common to all stories related to our Alert component.

We have the **`component`** key that allows us to define our component, the Alert, and a template. We use the **`twig`** function, and everything inside can be any valid Twig code we want. Here, we simply render the Alert component and give this component props: **`color`**, **`size`**, and **`position`**.

Then we define some **`argTypes`** that allow us to describe the controls we want under the story.

Then we define our first story:

```jsx
export const Default = {
  args: {
    color: 'blue',
    size: 'sm',
    position: 'top-left',
    message: 'Hello world!'
  },
}
```

And just like that, we have the following result!


![First story](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i2vkixz0v0ez19u01fcb.png)

You can play with the controls to test your component with different variations.

Then we can add more stories:

```jsx
export const Large = {
  args: {
    color: 'blue',
    size: 'lg',
    position: 'top-left',
    message: 'Hello world!'
  },
}

export const Error = {
  args: {
    color: 'red',
    size: 'lg',
    position: 'top-left',
    message: 'Hello world!'
  },
}

export const Success = {
  args: {
    color: 'green',
    size: 'lg',
    position: 'top-right',
    message: 'Good job!'
  },
}
```

So now, if we look at the menu of our Storybook, we have three stories:


![More stories](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qxxkka07orzn0oaycleh.png)

This is great, but we can go a bit further. Add the **`tags: ['autodocs']`** to your **`export default`**:

```jsx
export default {
  component: (args) => ({
    components: {Alert},
    template: twig`
      <twig:Alert color="{{ color }}" size="{{ size }}" position="{{ position }}">
        {{ message }}
      </twig:Alert>
  `
  }),
  ...
  tags: ['autodocs']
```

And just by adding this tag, Storybook creates a documentation page for us:


![Storybook doc](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eot77yt85mcymsx0rqa0.png)

And if that's not crazy enough, you can create a .mdx file:

```markdown
import {Canvas, Controls, Meta, Story} from "@storybook/blocks";
import * as AlertStories from "./Alert.stories";
 
<Meta of={AlertStories} />
 
# Alert
 
An Alert display information to the user.
 
<Story of={AlertStories.Default} />
 
Here are the properties you can use on the alert component:
 
<Controls of={AlertStories.Default} />
 
## Error
 
For error message you can use:
 
<Canvas of={AlertStories.Error} />
 
## Success
 
For success message you can use
 
<Story of={AlertStories.Success} />
```

As you can see in this .mdx file, we were able to import our stories into our documentation to make everything playable.

This is really cool! But you know what? This is only the beginning! We used Storybook to document a simple component, but Storybook can do much more. It can help with developing complex components or testing your components. We still have a lot to learn with Storybook, so stay tuned for the next article!

Thanks for reading. See you soon!