Search code examples
reactjsstorybook

Compound Component for Storybook Reactjs


Trying to write a simple compound component - a select component that contains an array of option components, but failing and not sure where the issue is.

( I've used https://storybook.js.org/tutorials/intro-to-storybook/react/en/composite-component/ for a starting point )

Select Component


import Option from "./Option";

export default function Select({ options, label, elementID, size, disabled }) {
    return (
        <div className="form-group">
            <label htmlFor={elementID}>{label}</label>
            <select className={`form-control ${size}`} id={elementID} disabled={disabled ? disabled : false}>
                {options.map(option => (
                    <Option key={option.value}>{option.label}</Option>
                ))}
            </select>
        </div>
    )
}

Select.propTypes = {
    label:         PropTypes.string,
    elementID:     PropTypes.string,
    size:          PropTypes.oneOf(["", "form-control-sm", "form-control-lg"]),
    disabled:      PropTypes.bool,
    options:       PropTypes.array,
}

Select.stories

import React from 'react';

import Select from "../components/Select";
import * as OptionStories from "./Option.stories";

export default {
    title: "Forms/Select",
    component: Select,
}

const Template = args => <Select {...args} />;

export const Default = Template.bind({});
Default.args = {
    label: "Select Label",
    elementID: "selectID",
    options: [
        { ...OptionStories.default.args.option, value: '1', label: 'Test'},
    ],
}

Option Component

import PropTypes from "prop-types"

function Option({ label, value, disabled }) {
    return (
        <option value={value} disabled={disabled ? disabled : false}>{label}</option>
    )
}

Option.propTypes = {
    label:         PropTypes.string,
    value:         PropTypes.string,
    disabled:      PropTypes.bool,
}

export default Option

Option.stories

import Option from "../components/Option"

export default {
    title: "Option",
    component: Option,
}

const Template = args => <Option {...args} />

export const Basic = Template.bind({})
Basic.args = {
    option: {
        value: "0",
        label: "Select Label",
    },
}

Solution

  • I figured it out thanks to https://www.robinwieruch.de/react-list-component/

    For anyone interested, the option component and story wasn't needed.

    In the select component I changed the return to

                    {options.map(item => {
                        return <option value={item.value}>{item.label}</option>
                    })}
    

    And in the select.story

    options: [
            {
                value: 'a',
                label: 'First Option'
            },
        ],