ShareAccess

components/ui/share-access.tsx

A Share button and the access sheet behind it, for a page other people need to open. Inviting is the first thing in reach, the people already on the page are a scrollable list underneath, and general link access sits at the bottom with the sentence that explains it, so nobody has to infer what a padlock means. The sheet is a native modal dialog: Escape closes it, focus starts in the email field and returns to the Share button afterwards, and the page behind goes inert. Every invite, access change and copy is announced, so no change is carried by colour or position alone.

Sharing a page

The usual case: an owner, two collaborators and one invite still pending. Inviting keeps the button's own label while the request runs; role changes and removal apply straight away.

Open to anyone with the link

General access carries its own sentence, so “anyone with the link can view” never has to be read out of an icon.

Ten people with access

The density case. The list scrolls inside a fixed maximum height with contained overscroll, while the invite row, general access and footer stay put.

Long names and addresses

Name and address truncate on their own lines with the full value kept in the title attribute, so a long address cannot push the access control off the row.

Nobody else yet

The empty state states what the current access is and what inviting would do, instead of showing an empty list.

Loading the list

The skeleton holds the row height for avatar, name and address, so the sheet does not jump when the list arrives. Inviting stays available while it loads.

The list failed to load

The error says what failed and what is still true, and keeps the invite form working, since inviting does not depend on the list.