Siteplane UI

Team settings

Edit the team profile and notification preferences, then save or reset the changes.

Markdown
Team settings
Manage your team profile and communication preferences.

Shown to everyone in the workspace.

Visibility

Notifications

Choose which updates your team receives.

Email updates
Important project and membership changes.
Weekly digest
A summary every Monday.
"use client";

import { Button } from "@/siteplane/components/button";
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/siteplane/components/card";
import {
  Field,
  FieldDescription,
  FieldError,
  FieldLabel,
} from "@/siteplane/components/field";
import { Form } from "@/siteplane/components/form";
import { Input } from "@/siteplane/components/input";
import {
  Select,
  SelectItem,
  SelectLabel,
  SelectPopup,
  SelectTrigger,
  SelectValue,
} from "@/siteplane/components/select";
import {
  SettingsList,
  SettingsListItem,
} from "@/siteplane/components/settings-list";
import { Switch } from "@/siteplane/components/switch";
import { Textarea } from "@/siteplane/components/textarea";
import { useState } from "react";

export default function Example() {
  const initial = {
    name: "Acme Design",
    description: "The team behind our product experience.",
    visibility: "private",
    email: true,
    digest: false,
  };
  const [settings, setSettings] = useState(initial);
  const [saved, setSaved] = useState(initial);
  const [resetCount, setResetCount] = useState(0);
  return (
    <Form
      className="grid w-full max-w-md gap-5"
      onReset={() => {
        setSettings(saved);
        setResetCount((count) => count + 1);
      }}
      onSubmit={(event) => {
        event.preventDefault();
        const next = { ...settings, name: settings.name.trim() };
        setSettings(next);
        setSaved(next);
      }}
    >
      <Card>
        <CardHeader>
          <CardTitle>Team settings</CardTitle>
          <CardDescription>
            Manage your team profile and communication preferences.
          </CardDescription>
        </CardHeader>
        <CardContent className="grid gap-4">
          <Field
            key={resetCount}
            name="name"
            validate={(value) =>
              typeof value === "string" && value.trim()
                ? null
                : "Enter a team name."
            }
          >
            <FieldLabel>Team name</FieldLabel>
            <Input
              required
              value={settings.name}
              onChange={(event) =>
                setSettings({ ...settings, name: event.target.value })
              }
            />
            <FieldDescription>
              Shown to everyone in the workspace.
            </FieldDescription>
            <FieldError>Enter a team name.</FieldError>
          </Field>
          <Field name="description">
            <FieldLabel>Description</FieldLabel>
            <Textarea
              value={settings.description}
              onChange={(event) =>
                setSettings({ ...settings, description: event.target.value })
              }
            />
          </Field>
          <Select
            name="visibility"
            value={settings.visibility}
            onValueChange={(value) => {
              if (value) setSettings({ ...settings, visibility: value });
            }}
          >
            <SelectLabel>Visibility</SelectLabel>
            <SelectTrigger>
              <SelectValue>
                {settings.visibility === "private"
                  ? "Private team"
                  : "Everyone in the workspace"}
              </SelectValue>
            </SelectTrigger>
            <SelectPopup>
              <SelectItem value="private">Private team</SelectItem>
              <SelectItem value="workspace">
                Everyone in the workspace
              </SelectItem>
            </SelectPopup>
          </Select>
        </CardContent>
      </Card>
      <SettingsList
        title="Notifications"
        description="Choose which updates your team receives."
      >
        <SettingsListItem
          title="Email updates"
          description="Important project and membership changes."
          control={(props) => (
            <Switch
              {...props}
              checked={settings.email}
              onCheckedChange={(email) => setSettings({ ...settings, email })}
            />
          )}
        />
        <SettingsListItem
          title="Weekly digest"
          description="A summary every Monday."
          control={(props) => (
            <Switch
              {...props}
              checked={settings.digest}
              onCheckedChange={(digest) => setSettings({ ...settings, digest })}
            />
          )}
        />
      </SettingsList>
      <div className="flex flex-wrap gap-2">
        <Button type="submit">Save changes</Button>
        <Button variant="outline" type="reset">
          Reset changes
        </Button>
      </div>
    </Form>
  );
}

Installation

Complete one-time setup, then install:

pnpm dlx shadcn@4.18.0 add @siteplane/team-settings

Files

The command installs src/components/team-settings.tsx and its component dependencies. Render its default export in your application. The registry item and the Code panel contain the same source.

Try the workflow

Change the team name, description, visibility, and notification settings. Save changes keeps the values as the new baseline; Reset changes restores it. An empty or whitespace-only team name shows “Enter a team name.”

Composition and adaptation

Form, Field, Input, Textarea, Select, Switch and SettingsList compose the editable settings screen.

AreaDetails
Datasettings contains the editable values; saved is the reset baseline.
CallbacksField validate checks the team name; Form onSubmit saves, and onReset restores saved and clears the validation message. Input, Select and Switch callbacks update settings.
Included statesEditable values, validation and reset.
Connect to your productReplace the local save with your service, add pending and server-error states, and enforce authorization on the server. Refreshing the page resets the local data.