A Share button that widens into its share panel: invite by email with a role, change each person's role, set who can open the link and copy it.
Installation
When to use
- Sharing a document, a board or a project with people: invite, roles and the link in one place, without leaving the page.
- Where roles matter: each person's role, and the link's access, is picked in a step inside the same panel.
When not to use
- Only a link to copy: a Copy Button is one click.
- Managing a whole team's members and permissions: that's a settings page.
Usage
Share Panel with your own data: a whole component you can paste as a page.
"use client"
import { SharePanel } from "@/components/dashral/pro/share-panel"
import { useState } from "react"
const team = [
{ id: "maya", name: "Maya Lindqvist", email: "maya@halcyon.studio", role: "editor", owner: true },
{ id: "leo", name: "Leo Hart", email: "leo@halcyon.studio", role: "viewer" },
]
export default function DocumentHeader() {
const [people, setPeople] = useState(team)
const [access, setAccess] = useState("restricted")
return (
<SharePanel
title="Q3 roadmap"
people={people}
onPeopleChange={setPeople}
onInvite={async (emails, role) => console.log("invite", emails, role)}
access={{ value: access, onValueChange: setAccess }}
link="https://example.com/d/q3-roadmap"
/>
)
}API reference
SharePanel
A Share button that widens into a share panel: invite by email with a role, change or remove each person's role, set who can open the link and copy it. Roles are picked in a step that slides into the same panel.
| Prop | Type | Default |
|---|---|---|
title | stringWhat's shared, for the panel's heading ("Share “Q3 roadmap”"). | — |
people | SharePerson[]The people with access (controlled), or the start of them. | — |
defaultPeople | SharePerson[] | [] |
onPeopleChange | (people: SharePerson[]) => void | — |
onInvite | (emails: string[], role: string) => void | Promise<void>Called on Invite with the emails and their role; may return a promise (a spinner shows meanwhile). | — |
roles | ShareRole[] | sample |
defaultRole | stringThe role an invite starts with; the first role by default. | — |
access | { value: string; onValueChange: (value: string) => void; options?: ShareAccessOption[] }Who else can open it, by link. | — |
link | stringThe link Copy link copies. | — |
label | stringThe button's words; "Share" by default. | "Share" |
side | "bottom" | "top" | "bottom" |
align | "start" | "end" | "end" |
width | numberThe panel's width, in px (never wider than the screen). | 400 |
className | string | — |
classNames | SharePanelClassNames | — |
type SharePerson
| Prop | Type | Default |
|---|---|---|
id | string | — |
name | string | — |
email | string | — |
avatar | string | — |
role | stringA role's value; the owner's is shown as "Owner" and can't be changed. | — |
owner | boolean | — |
pending | booleanInvited, not joined yet. | — |
type ShareRole
| Prop | Type | Default |
|---|---|---|
value | string | — |
label | string | — |
description | string | — |
type ShareAccessOption
| Prop | Type | Default |
|---|---|---|
value | string | — |
label | string | — |
description | string | — |
icon | React.ReactNode | — |
type SharePanelClassNames
| Prop | Type | Default |
|---|---|---|
root | string | — |
button | string | — |
panel | string | — |
Keyboard
| Keys | Action |
|---|---|
| Enter | In the email field: make a chip; with nothing typed, invite |
| ,orSpace | Make a chip too; a paste of several makes several |
| Backspace | In an empty email field: take the last chip back |
| ↑or↓ | Along the people's roles and the link's access; through a step's options |
| HomeorEnd | The first or last option in a step |
| ← | In a step: back, the focus where it was |
| Esc | Back from a step, or close; the focus returns to Share |
Accessibility
- The panel is a dialog (aria-modal) named "Share “<title>”"; each role button is named with its person ("Leo Hart: Can edit").
- A step's options are menu item radios with aria-checked; Remove access is its own item after a line.
- Copy link announces "Link copied" in a live region; people invited are marked Invited.
Motion
- The button widens into the panel (0.42 s) and, closing, shrinks back while the two crossfade.
- People invited slide into the list; a step slides in as the panel reshapes to it; Copy link's words swap for Copied, then back.
- Smooth tweens on [0.4, 0, 0.2, 1], never springs, except the small press. With reduced motion it only fades.