Skip to main content
The Controls Addon allows you to interact with component props dynamically through a graphical interface on your device. It’s the spiritual successor to the deprecated Knobs addon, offering a more powerful and flexible way to test different component states.

Installation

The Controls addon requires additional dependencies for form inputs:
1

Install the addon and dependencies

npm install -D @storybook/addon-ondevice-controls \
  @react-native-community/datetimepicker \
  @react-native-community/slider
The @react-native-community/datetimepicker and @react-native-community/slider packages are required for date and number range controls.
2

Register the addon

Add the addon to your .rnstorybook/main.ts configuration:
.rnstorybook/main.ts
import type { StorybookConfig } from '@storybook/react-native';

const main: StorybookConfig = {
  addons: ['@storybook/addon-ondevice-controls'],
};

export default main;

Control Types

The Controls addon automatically infers control types from your component props, but you can also specify them explicitly using argTypes.

Boolean

Renders a toggle switch for boolean values:
Boolean.stories.tsx
import type { Meta, StoryObj } from '@storybook/react-native';
import { Switch } from './Switch';

const meta = {
  component: Switch,
} satisfies Meta<typeof Switch>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Basic: Story = {
  args: {
    on: false,
  },
};

Text

Renders a text input field:
Text.stories.tsx
import type { Meta, StoryObj } from '@storybook/react-native';
import { Label } from './Label';

const meta = {
  component: Label,
  args: {
    name: 'Storyteller',
  },
} satisfies Meta<typeof Label>;

export default meta;

Number

Renders a numeric input with optional range slider:
Number.stories.tsx
import type { Meta, StoryObj } from '@storybook/react-native';
import { Counter } from './Counter';

const meta = {
  component: Counter,
  args: {
    age: 70,
    dollars: 12.5,
  },
  argTypes: {
    age: {
      step: 5,
      min: 0,
      max: 90,
      range: true, // Shows a slider
    },
    dollars: {
      min: 0,
      max: 100,
    },
  },
} satisfies Meta<typeof Counter>;

export default meta;

Color

Renders a color picker:
Color.stories.tsx
import type { Meta, StoryObj } from '@storybook/react-native';
import { ColorBox } from './ColorBox';

const meta = {
  component: ColorBox,
  argTypes: {
    color: {
      control: { type: 'color' },
    },
    backgroundColor: {
      control: { type: 'color' },
    },
  },
} satisfies Meta<typeof ColorBox>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Example: Story = {
  args: {
    color: '#a819b9',
    backgroundColor: '#eaeaea',
  },
};

Date

Renders a date picker:
Date.stories.tsx
import type { Meta, StoryObj } from '@storybook/react-native';
import { DateString } from './DateString';

const meta = {
  component: DateString,
  args: {
    birthday: new Date(2017, 0, 20),
  },
  argTypes: {
    birthday: {
      control: { type: 'date' },
    },
  },
} satisfies Meta<typeof DateString>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Basic: Story = {};

Select

Renders a dropdown selector:
Select.stories.tsx
import type { Meta, StoryObj } from '@storybook/react-native';
import { FruitDisplay } from './FruitDisplay';

const meta = {
  component: FruitDisplay,
  args: {
    fruit: 'apple',
  },
  argTypes: {
    fruit: {
      options: ['apple', 'banana', 'cherry'] as const,
      control: {
        type: 'select',
        labels: {
          apple: 'Apple',
          banana: 'Banana',
          cherry: 'Cherry',
        } as const,
      },
    },
  },
} satisfies Meta<typeof FruitDisplay>;

export default meta;

Radio

Renders radio buttons:
Radio.stories.tsx
import type { Meta, StoryObj } from '@storybook/react-native';
import { FruitDisplay } from './FruitDisplay';

const meta = {
  component: FruitDisplay,
  args: {
    otherFruit: 'watermelon',
  },
  argTypes: {
    otherFruit: {
      options: ['kiwi', 'guava', 'watermelon'] as const,
      control: {
        type: 'radio',
        labels: {
          kiwi: 'Kiwi',
          guava: 'Guava',
          watermelon: 'Watermelon',
        } as const,
      },
    },
  },
} satisfies Meta<typeof FruitDisplay>;

export default meta;

Object

Renders a JSON editor for complex objects:
Object.stories.tsx
import type { Meta, StoryObj } from '@storybook/react-native';
import { StyledBox } from './StyledBox';

const meta = {
  component: StyledBox,
  args: {
    customStyles: {
      borderWidth: 3,
      borderColor: '#000',
      padding: 10,
    },
  },
  argTypes: {
    customStyles: {
      control: { type: 'object' },
    },
  },
} satisfies Meta<typeof StyledBox>;

export default meta;

Array

Renders an array editor with comma-separated values:
Array.stories.tsx
import type { Meta, StoryObj } from '@storybook/react-native';
import { ItemList } from './ItemList';

const meta = {
  component: ItemList,
  args: {
    items: ['Laptop', 'Book', 'Whiskey'],
  },
  argTypes: {
    items: {
      separator: ',',
      // @ts-expect-error - Array is not a standard control type
      control: { type: 'array' },
    },
  },
} satisfies Meta<typeof ItemList>;

export default meta;
The array control type is specific to the React Native addon and may not be available in web Storybook.

Complete Example

Here’s a comprehensive example showing multiple control types:
ControlExample.stories.tsx
import type { Meta, StoryObj } from '@storybook/react-native';
import { ControlExample } from './ControlExample';

const meta = {
  component: ControlExample,
  args: {
    name: 'Storyteller',
    age: 70,
    fruit: 'apple',
    otherFruit: 'watermelon',
    dollars: 12.5,
    backgroundColor: '#eaeaea',
    items: ['Laptop', 'Book', 'Whiskey'],
    customStyles: {
      borderWidth: 3,
      borderColor: '#000',
      padding: 10,
    },
    nice: true,
    birthday: new Date(2017, 0, 20),
  },
  argTypes: {
    age: {
      step: 5,
      min: 0,
      max: 90,
      range: true,
    },
    fruit: {
      options: ['apple', 'banana', 'cherry'] as const,
      control: {
        type: 'select',
        labels: {
          apple: 'Apple',
          banana: 'Banana',
          cherry: 'Cherry',
        } as const,
      },
    },
    otherFruit: {
      options: ['kiwi', 'guava', 'watermelon'] as const,
      control: {
        type: 'radio',
        labels: {
          kiwi: 'Kiwi',
          guava: 'Guava',
          watermelon: 'Watermelon',
        } as const,
      },
    },
    dollars: {
      min: 0,
      max: 100,
    },
    birthday: {
      control: { type: 'date' },
    },
    backgroundColor: {
      control: { type: 'color' },
    },
    items: {
      // @ts-expect-error
      control: { type: 'array' },
    },
    customStyles: {
      control: { type: 'object' },
    },
  },
} satisfies Meta<typeof ControlExample>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Example: Story = {};

Migrating from Knobs

If you’re upgrading from the deprecated Knobs addon:
  1. Replace the package: Install @storybook/addon-ondevice-controls instead of the knobs addon
  2. Use Component Story Format (CSF): Move from imperative knob functions to declarative args and argTypes
  3. Update configuration: Replace knobs addon with controls in main.ts

Before (Knobs)

export const Button = () => {
  const label = text('Label', 'Hello Button');
  const disabled = boolean('Disabled', false);
  
  return <Button label={label} disabled={disabled} />;
};

After (Controls)

import type { Meta, StoryObj } from '@storybook/react-native';
import { Button } from './Button';

const meta = {
  component: Button,
  args: {
    label: 'Hello Button',
    disabled: false,
  },
} satisfies Meta<typeof Button>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Basic: Story = {};
For more migration examples, see the web Controls addon migration guide.

TypeScript Support

The Controls addon is fully typed and works seamlessly with TypeScript:
import type { Meta, StoryObj } from '@storybook/react-native';
import type { ComponentProps } from 'react';
import { MyComponent } from './MyComponent';

const meta = {
  component: MyComponent,
} satisfies Meta<typeof MyComponent>;

export default meta;

type Story = StoryObj<typeof meta>;

// Args are typed based on component props
export const Example: Story = {
  args: {
    // TypeScript will autocomplete and validate these
  },
};

Actions Addon

Log component interactions alongside controls

Web Controls Docs

Official web controls documentation (some features may differ)

Build docs developers (and LLMs) love