caliper uidocs

Direction sphere

Free

A direction input shaped like what it controls. Drag a light across a sphere and a sample beside it takes the highlight and drop shadow of that light. Two sliders carry the same two numbers, so the sphere is a convenience and never the only way in.

Installs components/ui/direction-sphere.tsxDepends on @radix-ui/react-slot, lucide-reactMotion none in component source
pnpm dlx shadcn@latest add @caliper/direction-sphere

315° azimuth 48° elevation

Raised

When to use #

Use it for

  • Light and shadow direction in a design tool, an emboss or a drop-shadow editor.
  • Any value that is two angles, such as azimuth and elevation.

Skip it when

  • A single angle; use a dial or a slider.
  • Exact placement of a point on a plane; use two number fields.

Decisions #

Why it is built this way, so you know what to keep when you change your copy.

Behaviour

The sliders are the accessible input
Azimuth runs 0 to 359 and elevation 5 to 90, each a native range with value text. The sphere takes the arrow keys as well, 5 degrees a press and 15 with Shift.
The numbers are always written
The readout names both angles in degrees, so the picture never carries the value alone.

Styling

The sphere is shaded by the light it sets
The middle is light from straight on and the rim is light from the side. Dragging has no easing, so reduced motion changes nothing.

Installation #

terminal
pnpm dlx shadcn@latest add @caliper/direction-sphere

Adds its 6 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.

Usage #

This is the code behind the preview above.

example.tsx
import { DirectionSphere } from "@/components/ui/direction-sphere"

export function DirectionSphereDemo() {
  return (
    <div className="w-full max-w-2xl">
      <DirectionSphere label="Light direction" />
    </div>
  );
}

API reference #

DirectionSphere

component
PropTypeDefaultDescription
labelstring"Light direction"
azimuthnumber—Controlled when set.
defaultAzimuthnumber315
elevationnumber—Controlled when set.
defaultElevationnumber48
onChange((value: LightDirection) => void)—
previewReactNode—Replaces the sample button. It sits on a stage that provides the light as custom properties.
statusDepthStatus"ready"
messagesDepthMessages—
onRetry(() => void)—
disabledboolean—
classNamestring—

Accessibility #

It exposes group semantics, with aria-roledescription, aria-label, aria-live and aria-valuetext kept in step with state. Changes that matter are announced through a live region.

KeyBehaviour
←Moves to the previous item or value.
→Moves to the next item or value.
↑Moves to the previous item or value.
↓Moves to the next item or value.

Motion #

It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.