Consent

@sushindustries/ui

A non-modal consent bar with equal-weight answers. It renders the question and reports the click; the host owns the SDK, the storage and the law.

6 min read
View as MarkdownEdit on GitHub

Storing the answer

ConsentConsentA non-modal consent bar with equal-weight answers. Vendor-agnostic: it renders the question and reports the click; the host owns the SDK and the answer.@sushindustries/ui · layout reports a click and nothing else. A minimal host looks like this:

const [status, setStatus] = useState<"pending" | "granted" | "denied">(
	() => (localStorage.getItem("consent") as typeof status) ?? "pending",
);

function record(next: "granted" | "denied") {
	localStorage.setItem("consent", next);
	setStatus(next);
}

<Consent open={status === "pending"} onAccept={() => record("granted")} onDecline={() => record("denied")}>
	...
</Consent>
tsx

Reading storage at initial state, rather than in an effect that flips open after mount, is what stops the bar flashing open for a returning visitor before the stored answer has been read.

Composing it

It renders position: fixed, docked to a corner by the stylesheet, so it does not need a positioned parent and can be mounted near the root of the page. Nothing about it assumes a particular ancestor.

When not to use it

Anywhere the law being satisfied requires blocking access until an answer is given. This component is non-modal on purpose - no backdrop, no focus trap, the page stays live - which is correct for "may I measure this" and wrong for a gate the visitor cannot get past.