shadcn.io is an independent project built on shadcn/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 Solid, Ark UI does not watch the scroll.
Installation
Anatomy

Usage
<Dialog>
<DialogTrigger asChild={props => <Button {...props()} variant="outline">Accept Terms</Button>} />
<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" onScroll={handleScroll}>
{terms.map(term => <div class="flex flex-col gap-2">
<h3 class="font-semibold">{term.title}</h3>
<p>{term.text}</p>
</div>)}
</div>
<DialogFooter>
<DialogClose asChild={props => <Button {...props()} disabled={!hasScrolledToBottom()}>I Agree</Button>} />
</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.
API Reference
Dialog
Sets asChild and props. The rest is on the Dialog page.
Button
Sets props, variant="outline" and disabled={!hasScrolledToBottom()}. The rest is on the Button page.





