HextaUI

Button group: Feedback inside a group

When a button’s label changes width during loading, success or error, the segments after it slide along instead of jumping.

"use client"

import * as React from "react"
import { IconChevronDown } from "@tabler/icons-react"

import { Button } from "@/components/ui/button"
import { ButtonGroup, ButtonGroupSeparator } from "@/components/ui/button-group"

function wait(ms: number) {
  return new Promise<void>((resolve) => setTimeout(resolve, ms))
}

async function fail(ms: number) {
  await wait(ms)
  throw new Error("Request failed")
}

export function ButtonGroupFeedback() {
  const [shouldFail, setShouldFail] = React.useState(false)

  return (
    <div className="flex flex-wrap items-center justify-center gap-3">
      <ButtonGroup aria-label="Save changes">
        <Button
          feedback
          loadingLabel="Saving changes"
          successLabel="All changes saved"
          errorLabel="Couldn't save"
          onClick={() => (shouldFail ? fail(900) : wait(900))}
        >
          Save
        </Button>
        <ButtonGroupSeparator />
        <Button size="icon" aria-label="More save options">
          <IconChevronDown />
        </Button>
      </ButtonGroup>
      <label className="flex items-center gap-2 text-sm text-muted-foreground">
        <input
          type="checkbox"
          checked={shouldFail}
          onChange={(event) => setShouldFail(event.target.checked)}
        />
        Fail next save
      </label>
    </div>
  )
}

This adds the example as components/examples/button-group/feedback.tsx, together with the Button group component and the HextaUI theme tokens it needs.

pnpm dlx shadcn@latest add https://hextaui.com/r/button-group-feedback.json

To add only the component, follow the Button group installation.

See them all, with keyboard support and accessibility notes, on the Button group page.