Skip to content

Sound Provider

Optional Foley sound effects, silent until enabled.

Upstream documentation

Examples

Off by default. This setting applies only to this preview.

Level
Notes
Tasks
Unavailable action

Selected action: None. Cancelled choices stay silent and keep the current fruit.

Installation

Run the Ninaero registry command to install the component and its dependencies, including shared theme styles.

Install Sound Provider
pnpm dlx shadcn@latest add 'https://ninaero.pages.dev/r/sound-provider.json'

Usage

A complete example using the installed component and hook paths.

Sound Provider usage
"use client";import { useId, useState } from "react";import { Button } from "@/components/ui/button";import { Checkbox } from "@/components/ui/checkbox";import { Combobox, ComboboxContent, ComboboxInput, ComboboxItem, ComboboxList } from "@/components/ui/combobox";import { Command, CommandInput, CommandItem, CommandList } from "@/components/ui/command";import { DropdownMenu, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";import { Field, FieldDescription, FieldGroup, FieldLabel, FieldTitle } from "@/components/ui/field";import { Progress, ProgressLabel, ProgressValue } from "@/components/ui/progress";import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";import { Slider } from "@/components/ui/slider";import { SoundProvider, useSound } from "@/components/ui/sound-provider";import { Switch } from "@/components/ui/switch";import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";import { createToastManager, Toaster } from "@/components/ui/toast";import { Toggle } from "@/components/ui/toggle";import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";const fruits = [  { value: "apple", label: "Apple" },  { value: "banana", label: "Banana" },  { value: "pear", label: "Pear" },];function SelectionExamples() {  const id = useId();  const [fruit, setFruit] = useState("apple");  const [action, setAction] = useState("None");  return (    <div className="flex flex-col gap-5">      <div className="flex flex-wrap gap-2">        <DropdownMenu>          <DropdownMenuTrigger render={<Button variant="outline" />}>            Choose a fruit          </DropdownMenuTrigger>          <DropdownMenuContent aria-label="Example fruit menu">            <DropdownMenuRadioGroup              value={fruit}              onValueChange={(value, details) => {                if (value === "cancelled") details.cancel();                else setFruit(value);              }}            >              {fruits.map((item) => (                <DropdownMenuRadioItem key={item.value} value={item.value}>                  {item.label}                </DropdownMenuRadioItem>              ))}              <DropdownMenuRadioItem value="cancelled">Cancelled choice</DropdownMenuRadioItem>              <DropdownMenuRadioItem value="unavailable" disabled>                Unavailable choice              </DropdownMenuRadioItem>            </DropdownMenuRadioGroup>          </DropdownMenuContent>        </DropdownMenu>        <Select          items={fruits}          value={fruit}          onValueChange={(value) => {            if (value) setFruit(value);          }}        >          <SelectTrigger aria-label="Example fruit select" className="w-40">            <SelectValue />          </SelectTrigger>          <SelectContent>            <SelectGroup>              {fruits.map((item) => (                <SelectItem key={item.value} value={item.value}>                  {item.label}                </SelectItem>              ))}            </SelectGroup>          </SelectContent>        </Select>      </div>      <Combobox items={["Apple", "Banana", "Pear"]} defaultValue="Apple">        <ComboboxInput aria-label="Example fruit search" placeholder="Find a fruit…" />        <ComboboxContent>          <ComboboxList>            {(item: string) => (              <ComboboxItem key={item} value={item}>                {item}              </ComboboxItem>            )}          </ComboboxList>        </ComboboxContent>      </Combobox>      <Field>        <FieldTitle id={`${id}-level`}>Level</FieldTitle>        <Slider aria-labelledby={`${id}-level`} defaultValue={40} />      </Field>      <RadioGroup aria-label="Example fruit radio group" value={fruit} onValueChange={setFruit}>        {fruits.map((item) => (          <Field key={item.value} orientation="horizontal">            <RadioGroupItem id={`${id}-${item.value}`} value={item.value} />            <FieldLabel htmlFor={`${id}-${item.value}`}>{item.label}</FieldLabel>          </Field>        ))}      </RadioGroup>      <ToggleGroup aria-label="Example layout" defaultValue={["list"]}>        <ToggleGroupItem value="list">List</ToggleGroupItem>        <ToggleGroupItem value="grid">Grid</ToggleGroupItem>      </ToggleGroup>      <Command className="max-w-sm">        <CommandInput aria-label="Filter example actions" placeholder="Filter actions…" />        <CommandList>          <CommandItem value="notes" onSelect={() => setAction("Notes")}>            Notes          </CommandItem>          <CommandItem value="tasks" onSelect={() => setAction("Tasks")}>            Tasks          </CommandItem>          <CommandItem value="unavailable" disabled>            Unavailable action          </CommandItem>        </CommandList>      </Command>      <FieldDescription>        Selected action: {action}. Cancelled choices stay silent and keep the current fruit.      </FieldDescription>    </div>  );}function FeedbackExamples() {  const [manager] = useState(() => createToastManager());  const [progress, setProgress] = useState(0);  return (    <Toaster toastManager={manager}>      <div className="flex flex-col gap-5">        <div className="flex flex-wrap gap-2">          <Button            sound={false}            onClick={() => manager.add({ title: "Example notification", type: "info" })}          >            Notification          </Button>          <Button            variant="secondary"            sound={false}            onClick={() => manager.add({ title: "Example success", type: "success" })}          >            Success          </Button>          <Button            variant="outline"            sound={false}            onClick={() => manager.add({ title: "Example error", type: "error" })}          >            Error          </Button>          <Button            variant="outline"            sound={false}            onClick={() => manager.add({ title: "Example warning", type: "warning" })}          >            Show warning          </Button>          <Button            variant="outline"            sound={false}            onClick={() => manager.add({ title: "Example loading task", type: "loading" })}          >            Show loading          </Button>        </div>        <Progress value={progress}>          <ProgressLabel>Example task</ProgressLabel>          <ProgressValue />        </Progress>        <Button          variant="outline"          sound={false}          onClick={() => setProgress((value) => (value === 100 ? 0 : value + 25))}        >          {progress === 100 ? "Reset progress" : "Advance progress"}        </Button>      </div>    </Toaster>  );}function SoundControls() {  const checkboxId = useId();  const switchId = useId();  const { play } = useSound();  return (    <div className="flex flex-col gap-5">      <div className="flex flex-wrap gap-2">        <Button>Save</Button>        <Button variant="secondary" sound={false} onClick={() => play("success")}>          Play success        </Button>        <Button variant="outline" sound={false}>          Quiet action        </Button>        <Button disabled>Disabled action</Button>        <Toggle variant="outline">Pin note</Toggle>      </div>      <FieldGroup>        <Field orientation="horizontal">          <Checkbox id={checkboxId} />          <FieldLabel htmlFor={checkboxId}>Include notes</FieldLabel>        </Field>        <Field orientation="horizontal">          <Switch id={switchId} />          <FieldLabel htmlFor={switchId}>Show hints</FieldLabel>        </Field>      </FieldGroup>      <Tabs defaultValue="selection">        <TabsList aria-label="Sound examples">          <TabsTrigger value="selection">Selection</TabsTrigger>          <TabsTrigger value="feedback">Feedback</TabsTrigger>        </TabsList>        <TabsContent value="selection">          <SelectionExamples />        </TabsContent>        <TabsContent value="feedback">          <FeedbackExamples />        </TabsContent>      </Tabs>    </div>  );}function SoundProviderPreview() {  const [enabled, setEnabled] = useState(false);  const id = useId();  return (    <SoundProvider enabled={enabled} theme="glass" volume={0.35}>      <div className="flex w-full flex-col gap-6">        <Field orientation="horizontal">          <Switch id={id} checked={enabled} onCheckedChange={setEnabled} sound={false} />          <div className="flex flex-col gap-1">            <FieldLabel htmlFor={id}>Sound effects</FieldLabel>            <FieldDescription>              Off by default. This setting applies only to this preview.            </FieldDescription>          </div>        </Field>        <SoundControls />      </div>    </SoundProvider>  );}export default function Demo() {  return <SoundProviderPreview />;}

API Reference

Ninaero exports and local defaults are listed below. See the upstream reference for inherited primitive props and additional composition examples.

SoundProvider

SoundProvider props
SoundProviderProps
enabled
defaultSoundSettings.enabled
volume
defaultSoundSettings.volume
theme
defaultSoundSettings.theme

useSound

Re-exported primitive; see the upstream API reference.

SoundCue

Re-exported primitive; see the upstream API reference.

SoundOptions

Re-exported primitive; see the upstream API reference.

SoundProviderProps

Exported type.

SoundTheme

Re-exported primitive; see the upstream API reference.

CueOptions

Exported type.

defaultSoundSettings

Exported value.

getSoundPitch

getSoundPitch props
number

createHoverSoundGate

Re-exported primitive; see the upstream API reference.

createSoundPlayer

createSoundPlayer props
() => Promise<SoundEngine>

SoundGroup

SoundGroup props
{ sound: boolean; children: ReactNode }

useControlSound

Re-exported primitive; see the upstream API reference.

HoverSound

HoverSound props
{  children: ReactElement;  sound?: boolean;}
sound
true

itemSoundOptions

itemSoundOptions props
HTMLElement | null

HighlightSound

HighlightSound props
{  state: State;  elementProps: useRender.ElementProps<"div">;  render?: useRender.RenderProp<State>;  sound?: boolean;}
sound
true

Source

Registry JSON