Liquid UI
Components

Liquid Alert

The iOS alert, a centred glass card that asks one question.

Installation

npx shadcn@latest add https://liquidcomponents.xyz/r/liquid-alert.json

Usage

import {
  LiquidAlert,
  LiquidAlertAction,
  LiquidAlertCancel,
  LiquidAlertContent,
  LiquidAlertTrigger,
} from "@/components/ui/liquid-alert"

<LiquidAlert>
  <LiquidAlertTrigger variant="destructive">Delete album</LiquidAlertTrigger>
  <LiquidAlertContent title="Delete “Summer”?" description="This album and its 48 photos will be removed.">
    <LiquidAlertCancel>Cancel</LiquidAlertCancel>
    <LiquidAlertAction destructive>Delete</LiquidAlertAction>
  </LiquidAlertContent>
</LiquidAlert>

The card springs in, and focus starts on Cancel so a stray Enter never confirms. Radix AlertDialog makes it modal and keeps it open until an action is chosen.

Examples

Three choices

Location access: not set

<LiquidAlertContent title="Allow “Weather” to use your location?">
  <LiquidAlertAction>Allow While Using App</LiquidAlertAction>
  <LiquidAlertAction variant="secondary">Allow Once</LiquidAlertAction>
  <LiquidAlertCancel>Don’t Allow</LiquidAlertCancel>
</LiquidAlertContent>

Three or more actions stack, like on iOS. Set stacked to choose either way.

Text field

  • Receipts
  • Travel
<LiquidAlertContent
  title="New Folder"
  description="Enter a name for this folder."
  onOpenAutoFocus={(event) => {
    event.preventDefault()
    input.current?.focus()
  }}
  body={<LiquidAlertInput ref={input} value={name} onChange={(event) => setName(event.target.value)} />}
>
  <LiquidAlertCancel>Cancel</LiquidAlertCancel>
  <LiquidAlertAction disabled={!name}>Save</LiquidAlertAction>
</LiquidAlertContent>

body sits between the text and the actions. Focus the field on open, and let Enter save.

Wait for the work

Signed in as maya@example.com

<LiquidAlert open={open} onOpenChange={(next) => !busy && setOpen(next)}>
  …
  <LiquidAlertAction
    destructive
    onClick={async (event) => {
      event.preventDefault() // keep it open
      setBusy(true)
      await signOut()
      setOpen(false)
    }}
  >
    {busy ? <Spinner /> : "Sign Out"}
  </LiquidAlertAction>
</LiquidAlert>

Call preventDefault in an action's onClick and the alert stays open until the work finishes.

API

LiquidAlertContent

PropTypeDefault
titleReactNodenone
descriptionReactNodenone
bodyReactNodenone
stackedbooleanthree or more actions
lensLiquidGlassOptionsnone

LiquidAlertAction takes destructive and any LiquidButton prop. LiquidAlertInput takes any input prop.

On this page