Storybook: onSubmit stripped for Forms

Created on 20 Apr 2016  路  15Comments  路  Source: storybookjs/storybook

Trying to test a button that allows form submissions:

import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
import Button from '../button';

storiesOf('Button', module)
  .add('submit for a form', () => (
    <div className="p4 center">
      <form
        onSubmit={ () => action('form submitted') }>
        <Button type="submit">Submit</Button>
      </form>
    </div>
  ));

It seems that onSubmit gets stripped when it loads in React Storybook. I've tried different combinations: wrapping it with a div, making it the root component, using a custom Form component, etc. In all cases the onSubmit is stripped out. Any idea what I'm doing wrong? Or are forms not supported by React Storybook?

Most helpful comment

You need to pass in just the call to action() not a function that calls it:

<form onSubmit={action('form submitted')}>

This doesn't prevent the default action on the form though, so the iFrame will reload. Not sure how you could handle this outside storing the created action:

const submitAction = action('form submitted');
storiesOf('Button', module)
  .add('submit for a form', () => (
    <div className="p4 center">
      <form
        onSubmit={ e => { e.preventDefault(); submitAction(e); }}>
        <Button type="submit">Submit</Button>
      </form>
    </div>
  ));

All 15 comments

You need to pass in just the call to action() not a function that calls it:

<form onSubmit={action('form submitted')}>

This doesn't prevent the default action on the form though, so the iFrame will reload. Not sure how you could handle this outside storing the created action:

const submitAction = action('form submitted');
storiesOf('Button', module)
  .add('submit for a form', () => (
    <div className="p4 center">
      <form
        onSubmit={ e => { e.preventDefault(); submitAction(e); }}>
        <Button type="submit">Submit</Button>
      </form>
    </div>
  ));

I see, thanks for explaining that.

I found a better way.

onSubmit={ e => { e.preventDefault(); action('form submitted')(e); }}>

So. We need a better action with a e.preventDefault integrated.

@hmontes You just inlined a variable, why do you think it's better?

@Hypnosphi Because if i have several buttons in a component (example. A modal with a Close button and a send form button) i can use different actions (action('Modal closed'), action('Submitted Form').

But you only need preventing default on form submit button

Yes. Because "action" don't have a natural way to do that. (I spend hours to find a way to prevent default an event in storybook)

If you have several forms, you may want to create a function like this:

const withPreventDefault = handler => e => {
  e.preventDefault();
  handler(e);
}

And use it like that:

onSubmit={ withPreventDefault(action('form submitted')) }

Yeah. But that function is INSIDE the component.

The solution is for the Story. If you have a presentational component and a container you want to disable the event OUTSIDE of the presentational component (And in this case. In the story) because the presentational components aren't classes.

Sorry, but I don't get what you're talking about. Please provide an examle

It seems I'm late to the party, but this is still a problem.

            <form
              onSubmit={(e) => {
                e.preventDefault();
                action('form submitted')(e);
              }}
            >
              <input type="text" />
              <Button type="submit">Submit Button</Button>
            </form>

We're not relegating the form submission to the onSubmit event on the form node, and not the onClick event on the Button. If the code doesn't use e.preventDefault(), the iframe then forwards off to the root iframe and borks the Storybook frame. It would be better for the action to prevent default.

@plummer-flex Feel free to add this to your codebase

import {action} from '@storybook/addon-actions`

export const actionWithPreventDefault = name => e => {
  e.preventDefault();
  action(name)(e);
}

@Hypnosphi I get the adding another wrapper function so as to not use an inline function, but what's the case for not modifying action to handle this on it's own?

Because increasing API surface for each possible usecase is impractical

import {action} from '@storybook/addon-actions`

export const actionWithPreventDefault = name => e => {
e.preventDefault();
action(name)(e);
}

Now that @storybook/addon-actions is part of the essentials, I'm not able to import action anymore (even though it is installed as a dependency already). I checked the new action page here: https://storybook.js.org/docs/react/essentials/actions and looks like this is now handled differently. I was able to add an event for a button click, but still can't find how to prevent default for an onSubmit event using the new way.

Using Storybook v6.1.5

To clarify, I do see a "submitted" event showing in the action panel, but it immediately redirects to a "No Preview" page.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

levithomason picture levithomason  路  3Comments

zvictor picture zvictor  路  3Comments

Jonovono picture Jonovono  路  3Comments

arunoda picture arunoda  路  3Comments

dnlsandiego picture dnlsandiego  路  3Comments