ui icon indicating copy to clipboard operation
ui copied to clipboard

Add auto loading state for `UButton`/`UForm`

Open maximepvrt opened this issue 1 year ago • 4 comments

Description

Currently, there is no built-in way to set a auto loading state for buttons in nuxt/ui when they are linked to a @click event or are the submit button of a UForm.

Proposal

Add a feature to nuxt/ui to enable a loading state for buttons. This should be configurable for:

  1. Buttons with @click events.
  2. Submit buttons of a UForm with a reference to the form.

This enhancement will improve user experience by preventing multiple submissions and indicating that an action is in progress.

Example

<UButton promise-loading @click="handleClick">
  Submit
</UButton>

<UForm ref="myForm" @submit="handleSubmit">
  <UButton :loading="myForm.promiseLoading" type="submit">
    Submit
  </UButton>
</UForm>

Benefits

  • Prevents multiple submissions.
  • Provides a better DX.

Additional context

No response

maximepvrt avatar Jun 20 '24 17:06 maximepvrt

I like the idea, but i think it would be a bit tricky since we don't have access to any information about event handlers using emits and can't really wait for it to resolve. (For example here: https://github.com/nuxt/ui/blob/dev/src/runtime/components/forms/Form.vue#L136).

The only solution I can think of is to replace the @submit / @click events by a prop with a callback function, but it feels a bit odd.

A dedicated composable maybe? Something like useAsyncData except in only returns a handle to execute the function and the loading state?

const { loading, execute: submit } = useLoading(async () => { /* ... */ })

romhml avatar Jun 21 '24 16:06 romhml

This can be achieved using VueUse's useAsyncState (https://vueuse.org/core/useAsyncState/) to wrap your event handlers:

const { isReady, execute } = useAsyncState(async () => { 
    // ...
  },
  null,
  { immediate: false },
)

romhml avatar Jun 21 '24 16:06 romhml

I found out that we can declare emits using props while exploring ways to implement this, so it's actually possible to do it without changing the way components are used 😄

Here's a sample implementation for v3: https://github.com/benjamincanac/ui3/pull/135/files

romhml avatar Jul 02 '24 16:07 romhml

So cool 🤩

maximepvrt avatar Jul 02 '24 22:07 maximepvrt