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 Svelte, Ark UI does not watch the scroll.
Installation
Anatomy

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





