Follow Mode

Follow-mode chrome — outlines a region with a participant's color and surfaces a stop-following chip. Install Follow Mode from the VLLNT UI registry with the shadcn CLI.

Report a bug

Follow-mode chrome — outlines a region with a participant's color and surfaces a stop-following chip. Part of the data-display family in VLLNT UI, it ships as a machine-readable registry entry — copy the source directly into your app with the shadcn CLI and own it, no runtime dependency on a component library.

Preview

Switch between light and dark to inspect the embedded Storybook preview.

Installation

Add Follow Mode to your project with the shadcn CLI. The source lands in your codebase, ready to adapt:

pnpm dlx shadcn@latest add https://ui.vllnt.ai/r/follow-mode.json

Source

"use client"; import type { ComponentPropsWithoutRef, ReactNode } from "react"; import { cn } from "../../lib/utils"; /** * Color theme for the follow ring + chip. * * @public */ export type FollowModeColor = | "amber" | "blue" | "emerald" | "purple" | "red" | "rose"; const PALETTE: Record<FollowModeColor, { chip: string; ring: string }> = { amber: { chip: "bg-amber-500 text-white", ring: "ring-amber-500" }, blue: { chip: "bg-blue-500 text-white", ring: "ring-blue-500" }, emerald: { chip: "bg-emerald-500 text-white", ring: "ring-emerald-500" }, purple: { chip: "bg-purple-500 text-white", ring: "ring-purple-500" }, red: { chip: "bg-red-500 text-white", ring: "ring-red-500" }, rose: { chip: "bg-rose-500 text-white", ring: "ring-rose-500" }, }; /** * Localizable strings. * * @public */ export type FollowModeLabels = { /** Aria-label for the follow chrome. Defaults to `"Follow mode"`. */ region?: string; /** Stop-following button copy. Defaults to `"Stop"`. */ stop?: string; }; const DEFAULT_LABELS = { region: "Follow mode", stop: "Stop", } as const satisfies Required<FollowModeLabels>; /** * Props for {@link FollowMode}. * * @public */ export type FollowModeProps = { /** Color theme. Defaults to `"blue"`. */ color?: FollowModeColor; /** Localizable strings. */ labels?: FollowModeLabels; /** Display name of the followed participant. */ name: ReactNode; /** Fires when the user picks the stop-following button. */ onStop?: () => void; } & Omit<ComponentPropsWithoutRef<"div">, "color">; /** * Follow-mode chrome. Wrap any region (typically the whole canvas) to * outline it with the followed participant's color and surface a * pinned chip + stop-following button. Pure presentation — the host * drives viewport sync and toggles the wrapper on / off. * * @example * ```tsx * <FollowMode color="emerald" name="Sam" onStop={stop}> * <CanvasView … /> * </FollowMode> * ``` * * @public */ export const FollowMode = ({ ref, ...props }: FollowModeProps & { ref?: React.Ref<HTMLDivElement> }) => { const { children, className, color = "blue", labels, name, onStop, ...rest } = props; const palette = PALETTE[color]; const resolvedLabels = { ...DEFAULT_LABELS, ...labels }; return ( <div aria-label={resolvedLabels.region} className={cn( "relative h-full w-full rounded-2xl ring-2 ring-inset", palette.ring, className, )} data-follow-color={color} ref={ref} {...rest} > <div className="pointer-events-auto absolute left-1/2 top-2 z-30 flex -translate-x-1/2 items-center gap-1 rounded-full px-2 py-0.5 text-[11px] font-semibold shadow-sm" data-follow-chip > <span className={cn( "inline-flex items-center gap-1 rounded-full px-1.5 py-0.5", palette.chip, )} > <span aria-hidden="true"></span> <span>Following {name}</span> </span> {onStop ? ( <button aria-label={resolvedLabels.stop} className="inline-flex h-5 items-center rounded-full border border-border bg-background px-2 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground hover:bg-accent focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" onClick={onStop} type="button" > {resolvedLabels.stop} </button> ) : null} </div> {children} </div> ); }; FollowMode.displayName = "FollowMode";

Stories

Explore every variant and state in the interactive Storybook:

Preview

Switch between light and dark to inspect the embedded Storybook preview.

Dependencies

  • @vllnt/ui@^0.3.0