shadcn.io is not affiliated with official shadcn/ui
Terms Consent Onboarding Block for Vue
An invoicing tool's terms dialog shown open over a drawn invoice: six clauses as accordion rows with a Plain and Legal switch, an I've read this box per clause, a read count, and a receipt with a real .txt download.
Installation
Overview
Ask for consent in a way people can read with this terms dialog for Vue with Ark UI. It opens from Quotehithe, an invoicing tool: a header with an outline Review terms button, a drawn invoice screen under a soft scrim, and under it a receipt band. The Dialog lists six clauses (Your content, Payments, Cancelling, Privacy, Changes, Disputes) as Accordion rows, any number open at once, over a Plain and Legal Toggle Group that switches every clause between a sentence in plain words and its legal wording. Each clause has an “I've read this” Checkbox, and a hairline counts them. Agree and continue is the one Shine Button: quiet until all six are read, never gated on scrolling. Agreeing fills the receipt with the terms version, the date and the clauses read, and Download receipt saves it as a .txt file.
FAQ
Why is the dialog already open, and what do I keep?
So you can see it without a click. On load the dialog is a copy drawn in place over the invoice: a native dialog element that isn't modal, so nothing is trapped or focused. Review terms opens the real Dialog, modal, with its focus trap, Escape and focus return, and the copy stays closed until a reload. Both show the same TermsContent, and what you ticked in place is there in the real one. In your app keep the Dialog and drop the copy: the "in-place" state, the scrim and the dialog element.
How do I change the clauses and the two wordings?
Edit CLAUSES: each has an id, a title, a plain sentence and the legal text. The switch reads from the same entry, so the two can't drift apart in the markup, but have a lawyer check that they mean the same thing; the text here is made up for the demo.
Why isn't agreeing gated on scrolling to the end?
Because scrolling proves nothing about reading. Each clause is opened and ticked on purpose, and the count (“4 of 6 read”) is visible the whole time. Pressing Agree early says how many are still unread and opens the next one.
Is the receipt real?
The file is: Download receipt builds a text file with a Blob and saves it, then revokes the link. Its content is the typed VERSION, a fixed accepted date and the clauses read. Nothing was agreed with anyone: in your app record the version, the time and the account on your server, and email the receipt from there.
Is it accessible from the keyboard and a screen reader?
Yes. The real dialog is named by its title and described by its sentence, focus starts inside and stays there, and Escape, Not now and the close button return focus to Review terms. Arrow keys move between clause rows. Each clause row is a button that says whether it is open, and each box is named for its clause.
How does it look on a phone?
The copy shown on load docks to the foot of the invoice like a bottom sheet, with Agree and continue on top of Not now, and the list scrolling above them. The real dialog keeps the Dialog's own phone layout, and the receipt stacks its three facts over the download button.