Let's talk about -driven development. We all do it. So, instead of fighting it, let's it with Storybook Actions. console.log upgrade Feature instability and mitigations Storybook actions are a feature of Storybook 6 and 7. There's an to make them work like conventional testing mocks. This would be a welcome change, IMO. active design proposal Knowing that a change is on the horizon, let's focus on the features of the current API that will remain (or migrate easily with codemods). Feature Overview In a fresh Storybook 7 installation ( ), we find two example components configured to use Storybook actions. sandboxes here The included Button stories log the common event — — when clicked. Logs can then be expanded to show full event details. onClick Heading stories also log events but this time with custom events and . onLogin onCreateAccount These events are logged when the respective buttons are clicked. Actions pair perfectly with . Interactions are a way to document component states thru simulated user input. Interactions trigger their corresponding actions. Storybook interactions Add actions with argTypes Let's define actions for the example Button component. Open the story file and locate component . meta Add an property if one doesn't exist. argTypes Add an property (this needs to match the component prop name). onClick Set the value to . (The logged text can be anything we like.) { action: "clicked" } // Button.stories.tsx // (surronding code omitted) const meta = { title: "Example/Button", component: Button, tags: ["autodocs"], argTypes: { backgroundColor: { control: "color" }, onClick: { action: "onClick" }, }, } satisfies Meta<typeof Button>; Now click your button in Storybook and watch the Actions log! Test actions with interactions Let's add an interaction to the example Button component. Create or find a new story. Add a function to the story object. play Within the , find the button. canvasElement then simulate a click event. // Button.stories.tsx // (surronding code omitted) export const Primary: Story = { args: { primary: true, label: "Button", }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); const button = await canvas.getByRole("button", { name: /Button/i, }); await userEvent.click(button); }, }; Now the story will run the interaction when it loads. Logging both the interaction and the action — in their respective tabs. Lessons learned -driven development is something I do when driving out a component implementation. It's a quick, cheap way to ensure that events are hooked up (early in the process). console.log But log statements has one : they live in component code. And I'm guilty of pushing a log (or a few dozen) into production. huge drawback Storybook actions let you validate implementation in story files, leaving component code alone. Also published . here