Skip to content

shadcn.io is an independent project built on shadcn/ui

Free

Terms and Conditions Dialog for Vue

A terms dialog that keeps I Agree off until the reader scrolls to the end of the six sections.

UI library: Ark UI

Accept Terms opens Terms and Conditions. Six numbered sections scroll in a fixed-height box. The description says to scroll to the bottom. I Agree stays off until the scroll reaches the end.

Use it when people should see the end of the terms before they accept. If a scroll check is too harsh, let them agree in an Alert Dialog. In Vue, Ark UI does not watch the scroll.

Preview

Preview width

Installation

MCP · Pro
Make your AI a shadcn expert
Your agent installs components, builds pages and restyles your app from one prompt, in Claude Code, Cursor or VS Code.
Part of Pro

Anatomy

Dialog anatomy: content, title, description, close, footer

Usage

<Dialog>
  <DialogTrigger :asChild="true">
    <Button variant="outline">Accept Terms</Button>
  </DialogTrigger>
  <DialogContent class="sm:max-w-lg">
    <DialogHeader>
      <DialogTitle>Terms and Conditions</DialogTitle>
      <DialogDescription>
        Please read and scroll to the bottom to accept.
      </DialogDescription>
    </DialogHeader>
    <div
      class="flex h-75 flex-col gap-4 overflow-y-auto pe-4 text-sm"
      @scroll="handleScroll"
    >
      <div v-for="term in terms" class="flex flex-col gap-2" :key="term.title">
        <h3 class="font-semibold">{{ term.title }}</h3>
        <p>{{ term.text }}</p>
      </div>
    </div>
    <DialogFooter>
      <DialogClose :asChild="true">
        <Button :disabled="!hasScrolledToBottom">I Agree</Button>
      </DialogClose>
    </DialogFooter>
  </DialogContent>
</Dialog>

FAQ

How is the end of the text detected?

The terms sit in a div with h-75 overflow-y-auto, and its scroll handler checks whether scrollHeight - scrollTop - clientHeight is under 10 pixels. Once it is, I Agree is enabled for good.

Is forcing a scroll good UX?

For legal agreements you must prove were shown, it's defensible. For everything else, a checkbox confirmation is friendlier.

Should the button say why it's disabled?

Yes: add a short line under the terms such as Scroll to the end to accept, and remove it once the button is enabled.

How is I Agree disabled?

The button takes disabled until the reader reaches the end. It's a DialogClose, so it closes the dialog once pressed.

Does it work with touch scrolling?

Yes, touch scrolling fires the same scroll events. A fast flick reaches the end without reading, which is a limit of the pattern.

Does the state reset when it reopens?

No. The state lives in the component that renders the dialog, so once the end is reached, I Agree stays enabled. Reset it when the dialog closes if every open should start over.

API Reference

Dialog

Sets asChild. The rest is on the Dialog page.

Button

Sets variant="outline" and disabled="!hasScrolledToBottom". The rest is on the Button page.