Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add loading spinner to Button #3254

Closed
davidicus opened this issue Jul 2, 2019 · 10 comments
Closed

Add loading spinner to Button #3254

davidicus opened this issue Jul 2, 2019 · 10 comments
Labels
status: inactive Will close if there's no further activity within a given time type: discussion 💬 type: enhancement 💡

Comments

@davidicus
Copy link
Contributor

davidicus commented Jul 2, 2019

Summary

Add a loading spinner to the current Carbon button component to indicate that the action that resulted from the button click is still running which will provide feedback to the user that their click has been registered and the app is running as expected.

Justification

UX enhancement. Our product has a use case to disable the button and provide a "performing action" indicator when button clicks are performing long running actions like network request, etc. We currently extend the carbon button and add a loading component to accomplish this.

Specific timeline issues / requests

We have extended the carbon button. This is just a request to contribute back to the carbon library.

Available extra resources

What resources do you have to assist this effort?

I have a PR to perform this work. #3255

@davidicus
Copy link
Contributor Author

davidicus commented Jul 9, 2019

@jeanservaas This is the most common scenario for us.

We have a list of functions that are running on our data. When you click on the list you can see the data they create in graphs alongside it. We have the option to create new functions
image

This will pop up a modal wizard that we take user through filling out the appropriate inputs for the function.

image

When we hit create we are keeping the modal open until we get a response from the server. On success the new function gets added to the list and any data it is creating can be viewed in the graphs. On failure, we want to be able to show an error message so the user can either make changes to the function they created or pick another type of function.

Without the loader the user does not have immediate feedback that their action was registered and depending on how long the response takes this can be pretty bad UX. User's will usually try to press the button again which would send a second request. We can stop this second request but it doesn't reassure the user that their request is being processed.

The alternative of optimistically adding the function to the list is filled with its own problems and requires a lot of code to make sure our tables are lining up with the database. Additionally, this new item will not have any data in the graph associated with it yet and may lead the user to think the function is broken. This also doesn't allow them to go back in the wizard to make changes.

By disabling the button and showing the spinner we are able to communicate to the user that their action was registered and the application is processing their request. If the response is success then the modal closes and they are able to interact with their new function. If it fails we are able to keep the modal open and allow them to rectify their error.

We already do client side validation for everything we can and only when this validation passes does it allow the submit/create button to be enabled.

@jeanservaas
Copy link
Collaborator

@davidicus thanks for putting so much effort and thinking into this.

Without the loader the user does not have immediate feedback that their action was registered and depending on how long the response takes this can be pretty bad UX.

I definitely see a use case for a progress button (with a loader), but we'd need to have clear visual spec for each of these phases in the user flow before we merged it into our library.

  • static (action to be performed)
  • progress (determinate or indeterminate)
  • success / failure

I'm not sure what the failure/success states would look like:

  • where would the error message go in relationship to the button? (I assume i would appear somewhere in the modal, but could this progress button ever be used outside of a modal?)
  • for the success state would the button loader resolve in a success check mark icon or would the modal simply disappear to reveal the new function in the list / new graphs?

I also think there might be other ways to deal with the progress phase:

By disabling the button and showing the spinner we are able to communicate to the user that their action was registered and the application is processing their request.

Disabling the button and the spinner for the progress phase spurs a few questions (I'm also assuming the progress button appears in that modal in this flow, so correct me if I'm wrong):

  • why isn't the rest of the modal disabled? Can I still interact with the "Previous" button? Are the other values read only at that point?
  • why is the spinner disabled, when it's the only thing that's active at the moment? The Facebook app log in flow uses a similar pattern... their button type ghosted as their indeterminate spinner pops up on their log in button... but the spinner itself is not disabled.
  • can you cancel the process while creating or would closing the modal stop the creation flow?

Just some quick sketches around actually changing the type in the button to also communicate that the action was registered.

image

@davidicus
Copy link
Contributor Author

@jeanservaas No problem, glad to contribute if I can.

I'm not sure what the failure/success states would look like:

  • where would the error message go in relationship to the button? (I assume i would appear somewhere in the modal, but could this progress button ever be used outside of a modal?)
  • for the success state would the button loader resolve in a success check mark icon or would the modal simply disappear to reveal the new function in the list / new graphs?

We use this performing action button in multiple places not just in modals. Particularly, we also use them in our tables as an inline action.

When in the modal we have the error message appear in the modal

image

In the table we inline an error message with a tooltip

image

On success, we deal with the response outside of the button and the action depends on the context. In modals, the modal will close and focus will be placed on the table. In tables when we archive we may animate the cell closed.

I also think there might be other ways to deal with the progress phase:

I am definitely open to variations here. For us, the pain point was just giving the user feedback during the action. How that feedback occurs is open. My only comment would be that loading bars, to me, seem to communicate downloading or uploading some content instead of an api endpoint being successfully hit and returned.

  • why isn't the rest of the modal disabled? Can I still interact with the "Previous" button? Are the other values read only at that point?

These are all good questions. The rest of the modal is not disabled except for the buttons. I imagine the thought was when the action button in a definite 'performing action' state that this would be enough to let the users know they could not interact with the modal. But you are absolutely right, we should probably disable the rest to prevent this from happening because someone will eventually try.

  • why is the spinner disabled, when it's the only thing that's active at the moment? The Facebook app log in flow uses a similar pattern... their button type ghosted as their indeterminate spinner pops up on their log in button... but the spinner itself is not disabled.

The thought was to just give additional indicator to the user that the button was busy. The change in pointer and graying out of the button helped with this. A separate styling of the button for in this state would probably be preferable.

  • can you cancel the process while creating or would closing the modal stop the creation flow?

Not once the request has been sent it will not be canceled.

@jeanservaas
Copy link
Collaborator

@davidicus

Thanks for the context and answers. I've been doing a lot of research on this kind of pattern and I have actually noticed (now that I'm looking!) a lot of progress buttons that disable on click with active spinners.

  • Usually found in a log in flow (Nyt.com, facebook etc.)
  • the disabled state is usually involves a subtle visual shift like a fade vs. a more dramatic color change

So I understand your need for this enhancement and I also understand why you've designed it as you have and why you want to avoid the loading bar here.

I've also noticed, at least in the log in flows where I've encountered these types progress buttons most, only the button communicates a disabled or processing state... the rest of the screen does not...as there's not usually time to interact with it anyway. How this will apply to your scenarios though... you would know best.

That said, it makes sense that the most immediate path forward (using existing Carbon tokens and Carbon styles) is to bring in the disabled state with an active spinner on top of it.

image

I don't love the design of it, but the logic is there and it's the most immediate path forward. In future maybe we could investigate a fade, or something more subtle for this experience, but we'd need to dedicate some design resources to it... which we don't have at the moment (probably you guys or us) and it seems like your need is immediate.

(i was sketching here... but again, we'd need tokens for this and a spinner variation... so it requires more investigation/work)

image

Also, a couple of things about the error inline notification in the modal:

image

I found this example really confusing for the following reasons:

  • I don't think we'd ever want two closable error notifications nested within one another
  • It looks like both the modal and the notification are errors that block progress
  • Not sure if the buttons just have placeholder text... but I'm not sure what I'd be saving there

A couple of ideas:

  • Use an Error Modal
    I think our system is in need of an Error Modal -- we've already gotten a few feature requests for this variant (if you have an error modal, you don't need the inline notifcation.

#2935
#2922

  • Use a field error
    I'm not really sure what content is inside the modal (your original example, not the error modal)... but it looked like there were several fields... maybe a table etc to set parameters... couldn't you also use a field error in this type of situation? The same as you would when a password is incorrect, or a table error, if there's a table inside the modal?

image

  • Modify the notification so it's more of a note and does not have the close functionality
    This is just spitballing, again, not sure of your content... but something like this could be a possibility if for some reason the error modal / field errors don't apply.

image

One last note... for your table error... make sure you're using consistent icons for warning and error messages and consistent colors.

Hope this helps!

@davidicus
Copy link
Contributor Author

@jeanservaas Thanks for your work on this.

I don't love the design of it, but the logic is there and it's the most immediate path forward. In future maybe we could investigate a fade, or something more subtle for this experience, but we'd need to dedicate some design resources to it... which we don't have at the moment (probably you guys or us) and it seems like your need is immediate.

To clarify, my need is not so immediate. We are already supporting an extended carbon button in our addons library that is sufficient for now. I wanted to contribute back to Carbon because I knew the need wasn't unique to IoT. Our implementation was intended as a quick fix and didn't really get the proper consideration. You have already brought up valid critiques. I do like your idea of just fading the background color of the button instead of the heavy gray color change.

image

  • I don't think we'd ever want two closable error notifications nested within one another
  • It looks like both the modal and the notification are errors that block progress
  • Not sure if the buttons just have placeholder text... but I'm not sure what I'd be saving there

This pic was misleading. Its from our storybook and wouldn't normally have the error message repeated in the title. All text is just filler text. This would more likely be a form with the error notification. And we do validate the fields with inline error messaging. The error message would only be for Server response error messages. Sorry about that confusion.

@scottmarcella
Copy link

@jeanservaas @davidicus

I see that this is almost a month old, but finding it now while doing some quick research to make sure the issue I wanted to open didn't exist already.. and here it is.

David - responding to your most recent comment: definitely not unique to IoT as you said. My design team in Systems also ran into this issue with almost the exact intended use case.

We've also come up with almost the exact solution on the error message side. Our solution for the loading is a little different than what was discussed here and I wanted to share. As seen below, when the primary button is clicked, it disappears, the form fields are disabled, and an inline loading spinner/message appears:

Screen Shot 2019-08-09 at 12 48 47 PM

If I can do anything to help move this forward, I can provide visual/UX support for this.

@asudoh
Copy link
Contributor

asudoh commented Aug 10, 2019

Hi 👋 I think our designers are not completely against the basic idea IIUC, and having an example (e.g. in our Storybook or in our website) will be an nice addition. I don't want it to be baked into <Button> though, for the sake of the principle of component doing one thing and letting component work together. Having contributors understand such direction seems to be the biggest thing for us to move forward.

@stale
Copy link

stale bot commented Sep 9, 2019

We've marked this issue as stale because there hasn't been any activity for a couple of weeks. If there's no further activity on this issue in the next three days then we'll close it. You can keep the conversation going with just a short comment. Thanks for your contributions.

@stale stale bot added the status: inactive Will close if there's no further activity within a given time label Sep 9, 2019
@stale
Copy link

stale bot commented Sep 12, 2019

As there's been no activity since this issue was marked as stale, we are auto-closing it.

@stale stale bot closed this as completed Sep 12, 2019
@AnandChowdhary
Copy link

@asudoh, would you consider re-opening this issue? I'd love to see a "loading" modifier on not just buttons, but also for example TextInput, anything that can have a loading state, for example on Beufy: https://buefy.org/documentation/input#types-and-states.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: inactive Will close if there's no further activity within a given time type: discussion 💬 type: enhancement 💡
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants