React Components

React components for building Settings views that match the Studio design system

React Components

The SDK provides pre-styled React components for building Settings views that match Studio's design system, including light and dark color schemes. Import from @telemetryos/sdk/react.

info Always use these components for Settings views. Raw HTML elements won't look correct in Studio.

Debounce Guidelines

Store hooks accept an optional debounce delay (default 0ms - immediate). Choose based on input type:

Input TypeDebounceReason
Text input250msWait for typing to pause
Textarea250msWait for typing to pause
Select/Dropdown0ms (default)Immediate feedback expected
Switch/Toggle0ms (default)Immediate feedback expected
Checkbox0ms (default)Immediate feedback expected
Radio0ms (default)Immediate feedback expected
Slider5msResponsive feel, reduced message traffic
Color picker5msResponsive feel while dragging

Usage:

// Text input - debounce to wait for typing to pause
const [isLoading, city, setCity] = useCityStoreState(250)

// Dropdown - immediate (default, no argument needed)
const [isLoading, league, setLeague] = useLeagueStoreState()

// Slider - responsive (5ms)
const [isLoading, volume, setVolume] = useVolumeStoreState(5)

Container & Layout

SettingsContainer

Root wrapper for all Settings content. Handles color scheme synchronization with Studio.

import { SettingsContainer } from '@telemetryos/sdk/react'

function Settings() {
  return (
    <SettingsContainer>
      {/* All settings content goes here */}
    </SettingsContainer>
  )
}

SettingsHeading

Section heading used to divide settings into logical sections. Can be used at the container level or inside a SettingsBox.

import { SettingsHeading, SettingsDivider } from '@telemetryos/sdk/react'

<SettingsHeading>Display Options</SettingsHeading>
{/* Fields for this section */}

<SettingsDivider />

<SettingsHeading>Advanced Settings</SettingsHeading>
{/* Fields for next section */}

SettingsBox

Bordered container, typically used for individual items in a repeatable list. Each item in a list gets its own box.

import { SettingsBox, SettingsHeading, SettingsButtonFrame } from '@telemetryos/sdk/react'

<SettingsHeading>Teams</SettingsHeading>

{teams.map((team, index) => (
  <SettingsBox key={index}>
    <SettingsHeading>Team {index + 1}</SettingsHeading>
    {/* Team fields */}
    <SettingsButtonFrame>
      <button onClick={() => removeTeam(index)}>Remove</button>
    </SettingsButtonFrame>
  </SettingsBox>
))}

<SettingsButtonFrame>
  <button onClick={addTeam}>+ Add Team</button>
</SettingsButtonFrame>

SettingsDivider

Horizontal rule separator between sections.

import { SettingsDivider } from '@telemetryos/sdk/react'

<SettingsDivider />

Field Structure

SettingsField, SettingsLabel

Wrapper for each form field with its label. SettingsField renders as a <label> element, so clicking the label text will activate the input inside.

import { SettingsField, SettingsLabel } from '@telemetryos/sdk/react'

<SettingsField>
  <SettingsLabel>Field Label</SettingsLabel>
  {/* Input component goes here */}
</SettingsField>

SettingsHint

Optional hint text displayed below a field input.

import { SettingsField, SettingsLabel, SettingsInputFrame, SettingsHint } from '@telemetryos/sdk/react'

<SettingsField>
  <SettingsLabel>API Key</SettingsLabel>
  <SettingsInputFrame>
    <input type="text" value={apiKey} onChange={(e) => setApiKey(e.target.value)} />
  </SettingsInputFrame>
  <SettingsHint>Found in the dashboard under Settings → API</SettingsHint>
</SettingsField>

SettingsError

Error message displayed below a field input.

import { SettingsField, SettingsLabel, SettingsInputFrame, SettingsError } from '@telemetryos/sdk/react'

<SettingsField>
  <SettingsLabel>Email</SettingsLabel>
  <SettingsInputFrame>
    <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} />
  </SettingsInputFrame>
  {error && <SettingsError>{error}</SettingsError>}
</SettingsField>

Text Inputs

SettingsInputFrame

Styled wrapper for text inputs.

import {
  SettingsContainer,
  SettingsField,
  SettingsLabel,
  SettingsInputFrame,
} from '@telemetryos/sdk/react'
import { useTeamStoreState } from '../hooks/store'

function Settings() {
  const [isLoading, team, setTeam] = useTeamStoreState(250) // 250ms debounce for text input

  return (
    <SettingsContainer>
      <SettingsField>
        <SettingsLabel>Team Name</SettingsLabel>
        <SettingsInputFrame>
          <input
            type="text"
            placeholder="Enter team name..."
            disabled={isLoading}
            value={team}
            onChange={(e) => setTeam(e.target.value)}
          />
        </SettingsInputFrame>
      </SettingsField>
    </SettingsContainer>
  )
}

SettingsTextAreaFrame

Styled wrapper for multiline text inputs.

import { SettingsTextAreaFrame } from '@telemetryos/sdk/react'
import { useDescriptionStoreState } from '../hooks/store'

const [isLoading, description, setDescription] = useDescriptionStoreState(250) // 250ms debounce for textarea

<SettingsField>
  <SettingsLabel>Description</SettingsLabel>
  <SettingsTextAreaFrame>
    <textarea
      placeholder="Enter description..."
      disabled={isLoading}
      value={description}
      onChange={(e) => setDescription(e.target.value)}
      rows={4}
    />
  </SettingsTextAreaFrame>
</SettingsField>

Selection Inputs

SettingsSelectFrame

Styled wrapper for dropdown selects.

import { SettingsSelectFrame } from '@telemetryos/sdk/react'
import { useLeagueStoreState } from '../hooks/store'

const [isLoading, league, setLeague] = useLeagueStoreState(0) // 0ms for immediate feedback

<SettingsField>
  <SettingsLabel>League</SettingsLabel>
  <SettingsSelectFrame>
    <select
      disabled={isLoading}
      value={league}
      onChange={(e) => setLeague(e.target.value)}
    >
      <option value="nfl">NFL</option>
      <option value="nba">NBA</option>
      <option value="mlb">MLB</option>
      <option value="nhl">NHL</option>
    </select>
  </SettingsSelectFrame>
</SettingsField>

SettingsSliderFrame

Styled wrapper for range sliders.

import { SettingsSliderFrame } from '@telemetryos/sdk/react'
import { useVolumeStoreState } from '../hooks/store'

const [isLoading, volume, setVolume] = useVolumeStoreState(5) // 5ms for responsive feel

<SettingsField>
  <SettingsLabel>Volume</SettingsLabel>
  <SettingsSliderFrame>
    <input
      type="range"
      min="0"
      max="100"
      disabled={isLoading}
      value={volume}
      onChange={(e) => setVolume(Number(e.target.value))}
    />
    <span>{volume}%</span>  {/* Optional value label */}
  </SettingsSliderFrame>
</SettingsField>

The frame uses flexbox layout, so you can optionally add a <span> after the input to display the current value.

SettingsSliderRuler

Optional ruler with tick labels displayed below a slider.

import { SettingsSliderFrame, SettingsSliderRuler } from '@telemetryos/sdk/react'

<SettingsField>
  <SettingsLabel>Quality</SettingsLabel>
  <SettingsSliderFrame>
    <input
      type="range"
      min="1"
      max="3"
      value={quality}
      onChange={(e) => setQuality(Number(e.target.value))}
    />
    <span>{quality}</span>
  </SettingsSliderFrame>
  <SettingsSliderRuler>
    <span>Low</span>
    <span>Medium</span>
    <span>High</span>
  </SettingsSliderRuler>
</SettingsField>

SettingsColorFrame

Styled wrapper for color picker inputs. Displays the color swatch alongside the hex value.

import { SettingsColorFrame } from '@telemetryos/sdk/react'
import { useColorStoreState } from '../hooks/store'

const [isLoading, color, setColor] = useColorStoreState(5) // 5ms for responsive feel while dragging

<SettingsField>
  <SettingsLabel>Brand Color</SettingsLabel>
  <SettingsColorFrame>
    <input
      type="color"
      disabled={isLoading}
      value={color}
      onChange={(e) => setColor(e.target.value)}
    />
    <span>{color}</span>
  </SettingsColorFrame>
</SettingsField>

Toggle Inputs

SettingsSwitchFrame, SettingsSwitchLabel

Styled wrapper for toggle switches.

import { SettingsSwitchFrame, SettingsSwitchLabel } from '@telemetryos/sdk/react'
import { useShowScoresStoreState } from '../hooks/store'

const [isLoading, showScores, setShowScores] = useShowScoresStoreState(0) // 0ms for immediate feedback

<SettingsField>
  <SettingsSwitchFrame>
    <input
      type="checkbox"
      role="switch"
      disabled={isLoading}
      checked={showScores}
      onChange={(e) => setShowScores(e.target.checked)}
    />
    <SettingsSwitchLabel>Show Live Scores</SettingsSwitchLabel>
  </SettingsSwitchFrame>
</SettingsField>

SettingsCheckboxFrame, SettingsCheckboxLabel

Styled wrapper for checkboxes.

import { SettingsCheckboxFrame, SettingsCheckboxLabel } from '@telemetryos/sdk/react'
import { useAutoRefreshStoreState } from '../hooks/store'

const [isLoading, autoRefresh, setAutoRefresh] = useAutoRefreshStoreState(0) // 0ms for immediate feedback

<SettingsField>
  <SettingsCheckboxFrame>
    <input
      type="checkbox"
      disabled={isLoading}
      checked={autoRefresh}
      onChange={(e) => setAutoRefresh(e.target.checked)}
    />
    <SettingsCheckboxLabel>Enable Auto-Refresh</SettingsCheckboxLabel>
  </SettingsCheckboxFrame>
</SettingsField>

SettingsRadioFrame, SettingsRadioLabel

Styled wrapper for radio button groups.

import { SettingsRadioFrame, SettingsRadioLabel } from '@telemetryos/sdk/react'
import { useDisplayModeStoreState } from '../hooks/store'

const [isLoading, displayMode, setDisplayMode] = useDisplayModeStoreState(0) // 0ms for immediate feedback

<SettingsField>
  <SettingsLabel>Display Mode</SettingsLabel>
  <SettingsRadioFrame>
    <input
      type="radio"
      name="displayMode"
      value="compact"
      disabled={isLoading}
      checked={displayMode === 'compact'}
      onChange={(e) => setDisplayMode(e.target.value)}
    />
    <SettingsRadioLabel>Compact</SettingsRadioLabel>
  </SettingsRadioFrame>
  <SettingsRadioFrame>
    <input
      type="radio"
      name="displayMode"
      value="expanded"
      disabled={isLoading}
      checked={displayMode === 'expanded'}
      onChange={(e) => setDisplayMode(e.target.value)}
    />
    <SettingsRadioLabel>Expanded</SettingsRadioLabel>
  </SettingsRadioFrame>
</SettingsField>

Actions

SettingsButtonFrame

Styled wrapper for action buttons.

import { SettingsButtonFrame } from '@telemetryos/sdk/react'

<SettingsButtonFrame>
  <button onClick={handleReset}>Reset to Defaults</button>
</SettingsButtonFrame>

Component Reference

ComponentPurpose
SettingsContainerRoot wrapper, handles color scheme
SettingsHeadingSection heading
SettingsBoxContainer for list items
SettingsDividerHorizontal separator
SettingsFieldWrapper for each field (renders as label)
SettingsLabelField label
SettingsHintHelp text below a field
SettingsErrorError message below a field
SettingsInputFrameText input wrapper
SettingsTextAreaFrameMultiline text wrapper
SettingsSelectFrameDropdown wrapper
SettingsSliderFrameRange slider wrapper
SettingsSliderRulerTick labels below a slider
SettingsColorFrameColor picker wrapper
SettingsSwitchFrameToggle switch wrapper
SettingsSwitchLabelToggle switch label
SettingsCheckboxFrameCheckbox wrapper
SettingsCheckboxLabelCheckbox label
SettingsRadioFrameRadio button wrapper
SettingsRadioLabelRadio button label
SettingsButtonFrameAction button wrapper

What’s Next