> ## Documentation Index
> Fetch the complete documentation index at: https://rive.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Data Binding

> Connect your code to bound editor elements using View Models

export const Demos = ({examples, runtime, columns = 2, children, childrenIndex = 0, learnByExample = false}) => {
  const examplesData = {
    ikConstraint: {
      title: 'IK Constraints',
      description: 'Check out this example to see IK constraints in action.',
      image: "https://static.rive.app/docs/ik-constraint.gif",
      stateMachines: "State Machine 1",
      links: {
        editor: "https://rive.app/community/files/28080-53039-ik-constraint/"
      }
    },
    cachingARiveFile: {
      title: 'Caching a Rive File',
      description: 'Load the .riv into memory once, use it multiple times.',
      riv: 'https://static.rive.app/rivs/rives_animated_emojis.riv',
      stateMachines: "State Machine 1",
      artboard: "Emoji_package",
      links: {
        web: "https://codesandbox.io/p/sandbox/rive-js-caching-a-rive-file-g675my?file=%2Fsrc%2Findex.ts%3A9%2C1",
        react: "https://codesandbox.io/p/sandbox/rive-react-caching-a-rive-file-53gmdf?file=%2Fsrc%2FApp.tsx"
      },
      source: ["https://rive.app/marketplace/24644-46045-caching-a-rive-file-at-runtime/"]
    },
    dataBindingArtboards: {
      title: 'Data Binding Artboards',
      description: 'Swap an artboard with another artboard from the same .riv or one loaded at runtime.',
      image: '/images/runtimes/rive-data-bind-components.webp',
      links: {
        web: 'https://codesandbox.io/p/sandbox/rive-js-data-binding-artboards-jx3pf9?file=%2Fsrc%2Findex.mjs%3A5%2C19',
        react: 'https://codesandbox.io/p/sandbox/rive-react-data-binding-artboards-kmvzh8?file=%2Fsrc%2FApp.tsx',
        flutter: 'https://github.com/rive-app/rive-flutter/blob/master/example/lib/examples/databinding_artboards.dart',
        reactNative: 'https://github.com/rive-app/rive-nitro-react-native/blob/main/example/src/demos/DataBindingArtboardsExample.tsx',
        android: "https://github.com/rive-app/rive-android/blob/master/app/src/main/java/app/rive/runtime/example/ComposeArtboardBindingActivity.kt"
      },
      source: ["https://rive.app/marketplace/24641-46042-data-binding-artboards/", "https://rive.app/marketplace/24642-47536-data-binding-artboards/"]
    },
    dataBindingImages: {
      title: 'Data Binding Images',
      description: 'Replace images at runtime using data binding images with javascript.',
      image: '/images/runtimes/rive-db-images.webp',
      links: {
        web: 'https://codesandbox.io/p/sandbox/objective-cohen-sqwh9q?file=%2Fsrc%2Findex.ts',
        flutter: 'https://github.com/rive-app/rive-flutter/blob/master/example/lib/examples/databinding_images.dart',
        android: "https://github.com/rive-app/rive-android/blob/master/app/src/main/java/app/rive/runtime/example/ComposeImageBindingActivity.kt"
      },
      source: ["https://rive.app/marketplace/25472-47537-data-binding-images/"]
    },
    dataBindingLists: {
      title: 'Data Binding Lists',
      description: 'Add, remove, edit, and swap items in your data binding list.',
      image: '/images/runtimes/rive-db-lists.webp',
      links: {
        web: 'https://codesandbox.io/p/sandbox/suspicious-hertz-2lg4m8?file=%2Fsrc%2Findex.ts',
        react: 'https://codesandbox.io/p/sandbox/rive-react-data-binding-lists-4msh9z?file=%2Fsrc%2FApp.tsx',
        flutter: 'https://github.com/rive-app/rive-flutter/blob/master/example/lib/examples/databinding_lists.dart',
        android: "https://github.com/rive-app/rive-android/blob/master/app/src/main/java/app/rive/runtime/example/ComposeListActivity.kt"
      },
      source: ["https://rive.app/marketplace/25474-47539-data-binding-lists/"]
    },
    dataBindingQuickStart: {
      title: "Data Binding",
      description: "Get started with Data Binding at runtime.",
      image: "/images/runtimes/rewards.gif",
      links: {
        flutter: "https://github.com/rive-app/rive-flutter/blob/master/example/lib/examples/databinding.dart",
        reactNative: "https://github.com/rive-app/rive-react-native/blob/main/example/app/(examples)/DataBinding.tsx",
        unity: "https://github.com/rive-app/rive-unity-examples/blob/main/getting-started/Assets/RewardsController.cs",
        apple: "https://github.com/rive-app/rive-ios/blob/main/Example-iOS/Source/Examples/SwiftUI/RewardsView.swift",
        android: "https://github.com/rive-app/rive-android/blob/master/app/src/main/java/app/rive/runtime/example/ComposeDataBindingActivity.kt"
      },
      source: ["https://rive.app/marketplace/25475-47540-data-binding-demo/"]
    },
    dataBindingSolos: {
      title: "Data Binding Solos",
      description: "Control solos at runtime using strings, numbers, or enums.",
      image: '/images/runtimes/data-binding-solos.gif',
      links: {
        react: "https://codesandbox.io/p/sandbox/rive-react-controlling-solos-at-runtime-ctcnlx?file=%2Fsrc%2FApp.tsx"
      },
      source: ["https://rive.app/marketplace/24643-46044-data-binding-solos/"]
    },
    googleAppAds: {
      title: "Google App Ads",
      description: "How to make an interactive Google App with Rive.",
      image: "/images/runtimes/google-app-ads.png",
      links: {
        mobile: "https://github.com/rive-app/rive-use-cases/tree/main/rive-google-ads"
      }
    },
    layouts: {
      title: "Responsive Layouts",
      description: "Create responsive layouts that adapt to different screen sizes.",
      riv: "https://static.rive.app/rivs/layouts_demo.riv",
      stateMachines: "State Machine 1",
      artboard: "Demo",
      links: {
        web: "https://codesandbox.io/p/devbox/rive-responsive-layout-js-forked-m77nlw",
        react: "https://codesandbox.io/p/devbox/rive-responsive-layouts-react-forked-nmpv39?file=%2Fsrc%2FApp.tsx",
        flutter: "https://github.com/rive-app/rive-flutter/blob/master/example/lib/examples/responsive_layouts.dart",
        reactNative: "https://github.com/rive-app/rive-react-native/blob/main/example/app/(examples)/ResponsiveLayout.tsx",
        android: "https://github.com/rive-app/rive-android/blob/master/app/src/main/java/app/rive/runtime/example/ComposeLayoutActivity.kt"
      },
      source: ["https://rive.app/marketplace/24638-46038-layouts-demo/"]
    },
    fontsHostedCompressed: {
      title: 'Load a Compressed Font for Web',
      description: 'Dynamically load a font asset from a hosted location with compression.',
      image: '/images/runtimes/brotli-compressed-fonts.webp',
      links: {
        react: 'https://codesandbox.io/p/sandbox/prod-sound-6yc5xl?file=%2Fsrc%2FApp.tsx%3A19%2C1'
      },
      source: ["https://rive.app/marketplace/25473-47538-loading-compressed-fonts-web/"]
    },
    quickStart: {
      title: "Data Binding Quick Start",
      image: '/images/runtimes/quick-start.gif',
      description: 'Load and control your Rive (.riv) file.',
      links: {
        web: 'https://codesandbox.io/p/sandbox/rive-quick-start-js-xmwcm6?file=%2Fsrc%2Findex.ts',
        react: 'https://codesandbox.io/p/sandbox/rive-react-quick-start-4xy76h?file=%2Fsrc%2FApp.tsx%3A77%2C14',
        reactJs: 'https://codesandbox.io/p/devbox/rive-react-vanilla-js-quick-start-kz66t4?file=%2Fsrc%2FApp.tsx%3A53%2C7',
        reactNative: 'https://github.com/rive-app/rive-nitro-react-native/blob/main/example/src/demos/QuickStart.tsx',
        unity: '/game-runtimes/unity/tutorials/health-bar'
      },
      source: ["https://rive.app/marketplace/24637-46037-health-bar-data-binding-quick-start/"]
    },
    quickStartReact: {
      title: "Data Binding Quick Start",
      image: '/images/runtimes/quick-start.gif',
      description: 'Load and control your Rive (.riv) file.',
      links: {
        react: 'https://codesandbox.io/p/sandbox/rive-react-quick-start-4xy76h?file=%2Fsrc%2FApp.tsx%3A77%2C14',
        reactJs: 'https://codesandbox.io/p/devbox/rive-react-vanilla-js-quick-start-kz66t4?file=%2Fsrc%2FApp.tsx%3A53%2C7'
      },
      source: ["https://rive.app/marketplace/24637-46037-health-bar-data-binding-quick-start/"]
    },
    scriptingDrawingShapes: {
      title: "Drawing with Scripting",
      image: "https://static.rive.app/docs/drawing-demo.png",
      description: "Draw a squirkle, a star, and an animated wave with scripting.",
      links: {
        editor: "https://rive.app/community/files/25751-48087-drawing-shapes-with-scripting"
      }
    },
    scriptingMasonry: {
      title: "Masonry Layout",
      image: "https://static.rive.app/docs/masonry.png",
      description: "Create a masonry layout using a Layout script.",
      links: {
        editor: "https://rive.app/community/files/25826-masonry-layout/"
      }
    },
    scriptingParticleEmitter: {
      title: "Particle Emitter",
      riv: "https://static.rive.app/rivs/particle-demo.riv",
      artboard: "Demo",
      description: "A small, self contained particle system for Rive node and layout scripts.",
      links: {
        editor: "https://rive.app/community/files/28062-53012-particle-librar/"
      }
    },
    scriptingTippingConverter: {
      title: "Custom Converter",
      image: "https://static.rive.app/docs/tipping-scripting-converter.gif",
      description: "Calculate the bill total using the converter's input value added to data binding values.",
      links: {
        editor: "https://uat.rive.app/community/files/610-1126-custom-converter-with-scripting"
      }
    },
    scriptingUnitTesting: {
      title: "Unit Testing",
      image: "https://static.rive.app/docs/scripting-default-thumb.png",
      description: "This hands-on example demonstrates unit testing rgbToHex and hexToRgb color utilities.",
      links: {
        editor: "https://rive.app/community/files/25752-48088-test-script"
      }
    },
    scriptingSnakeGame: {
      title: "Snake - Complete Game",
      image: "https://static.rive.app/docs/snake-game.png",
      description: "Check out this complete game built entirely with Rive using scripting.",
      links: {
        editor: "https://rive.app/community/files/25748-48110-snake-game/"
      }
    },
    scriptingMultiTouch: {
      title: "Tracking Multi-touch",
      image: "https://static.rive.app/docs/scripting-default-thumb.png",
      description: "Keep track of every finger.",
      links: {
        editor: "https://rive.app/community/files/25754-48090-multi-touch-with-scripting"
      }
    },
    scriptingNestedPointers: {
      title: "Nested Pointer Events",
      image: "https://static.rive.app/docs/scripting-default-thumb.png",
      description: "Pass pointer events from the parent component to the instantiated children.",
      links: {
        editor: "https://rive.app/community/files/25750-48086-scripting-nested-pointer-events/"
      }
    },
    scriptingBoilPathEffect: {
      title: "Boiling Path Effect",
      image: "https://static.rive.app/docs/boiling-effect.gif",
      description: "Apply a boiling effect to any path using scripting.",
      links: {
        editor: "https://rive.app/community/files/25767-48113-scripting-path-effect-boil"
      }
    },
    scriptingTextPathEffect: {
      title: "Text Path Effect",
      image: "https://static.rive.app/docs/text-path-effect.gif",
      description: "Control a text path using scripting.",
      links: {
        editor: "https://rive.app/community/files/25823-text-path-effects/"
      }
    },
    scriptingDrawImages: {
      title: "Render an Image with Scripting",
      image: "https://static.rive.app/docs/render-image-with-scripting.jpg",
      description: "Draw an image, give it transforms, control its mesh, and add clipping all through scripting.",
      links: {
        editor: "https://rive.app/community/files/26406-draw-an-image-with-scripting"
      }
    },
    scriptingSlotMachine: {
      title: "Slot Machine - Complete Game",
      image: "https://static.rive.app/docs/slot-machine.png",
      description: "Build a complete casino game using scripting.",
      links: {
        editor: "https://rive.app/community/files/25759-slot-machine-game-with-scripting/"
      }
    },
    scriptingLists: {
      title: "Scripting Lists",
      image: "/images/runtimes/rive-db-lists.webp",
      description: "Add, remove, edit, and swap items in your data binding list using Rive scripting.",
      links: {
        editor: "https://rive.app/community/files/27098-51051-scripting-lists"
      }
    },
    scriptingPlinko: {
      title: "Plinko - Complete Game",
      image: "https://static.rive.app/docs/scripting-plinko-game.png",
      description: "Build a complete Plinko game using Layout, Node, and Path Effect scripts.",
      links: {
        editor: "https://rive.app/marketplace/25772-blinko-scripted-game/"
      }
    },
    constraints: {
      title: "Constraints",
      image: "https://static.rive.app/docs/constraints.gif",
      description: "Transform, Translate, Scale, and Rotation Constraints.",
      links: {
        editor: "https://rive.app/community/files/28081-53040-constraints/"
      }
    }
  };
  const runtimesInOrder = ['web', 'react', 'reactJs', 'reactNative', 'flutter', 'apple', 'android', 'unity', 'unreal', 'mobile', 'editor'];
  const runtimeTitles = {
    web: 'Web',
    reactJs: 'React (Imperative)',
    react: 'React',
    reactNative: "React Native",
    flutter: 'Flutter',
    apple: 'Apple',
    android: 'Android',
    unity: 'Unity',
    unreal: 'Unreal',
    mobile: 'Mobile',
    editor: 'Try in Rive'
  };
  const riveInstances = useRef([]);
  const initRives = () => {
    const rive = window.rive;
    examples.forEach(example => {
      const {riv, stateMachines = "State Machine 1", artboard} = examplesData[example];
      if (riv) {
        const canvasId = `rive-canvas-${example}`;
        const canvas = document.getElementById(canvasId);
        if (canvas) {
          const r = new rive.Rive({
            src: riv,
            stateMachines,
            canvas,
            artboard,
            autoBind: true,
            autoplay: true,
            Layout: new rive.Layout({
              fit: rive.Fit.Layout
            }),
            onLoad: () => {
              r.resizeDrawingSurfaceToCanvas();
              riveInstances.current.push(r);
            }
          });
        }
      }
    });
  };
  useEffect(() => {
    if (window.rive) {
      initRives();
      return;
    }
    const checkRive = () => {
      if (window.rive) {
        initRives();
        window.removeEventListener("rive-loaded", checkRive);
      }
    };
    const handleResize = () => {
      riveInstances.current.forEach(instance => {
        instance.resizeDrawingSurfaceToCanvas();
      });
    };
    window.addEventListener("rive-loaded", checkRive);
    window.addEventListener("resize", handleResize);
    return () => {
      window.removeEventListener("rive-loaded", checkRive);
      window.removeEventListener("resize", handleResize);
      riveInstances.current.forEach(instance => {
        instance.cleanup();
      });
    };
  }, []);
  const RuntimeLink = ({link, runtime}) => {
    if (!link) return null;
    if (runtime === 'editor') {
      link = `${link}?utm_source=docs&utm_medium=docs_demo_card`;
    }
    return <a href={link} target="_blank" className="cursor-pointer border border-neutral-600 hover:border-white rounded-[4px] text-14 py-1 px-5 mr-[10px] mb-[10px]">
        {runtimeTitles[runtime]}
      </a>;
  };
  const CardContainer = ({children: content}) => {
    return <div className="flex flex-col card block font-normal group relative my-2 ring-2 ring-transparent rounded-2xl bg-white dark:bg-background-dark border border-gray-950/10 dark:border-white/10 overflow-hidden w-full">
        {content}
      </div>;
  };
  const getSrc = imageSrc => {
    if (location.hostname === "localhost" && imageSrc.startsWith("/images/")) {
      return imageSrc;
    } else if (imageSrc.startsWith('https:')) {
      return imageSrc;
    }
    return `https://rive.app/docs${imageSrc}`;
  };
  return <div className={`
        card-group not-prose grid gap-x-4
        grid-cols-1
        ${columns >= 2 && "md:grid-cols-2"}
        ${columns >= 3 && "xl:grid-cols-3 xl:w-[67rem] xl:max-w-[calc(100vw-25rem)]"}
      `}>
      {examples.map((example, index) => {
    const {title, image, links, description, source, riv} = examplesData[example];
    const canvasId = `rive-canvas-${example}`;
    return <>
            {index === childrenIndex && children}
            <CardContainer key={canvasId}>
              <div className="w-full h-0 relative pb-[75%]">
                <div className="absolute inset-0">
                  {image && <img alt={title} className="w-full object-cover object-center" src={getSrc(image)} />}

                  {riv && !image && <canvas id={canvasId} style={{
      width: "100%",
      height: "100%"
    }} />}
                </div>
              </div>
              <div className="flex flex-grow flex-col px-6 py-5 relative" data-component-part="card-content-container">
                <div className="flex flex-col grow">
                  <h2 className="not-prose font-semibold text-base text-gray-800 dark:text-white" data-component-part="card-title">{learnByExample ? "Learn by Example" : title}</h2>

                  <div className="flex flex-col grow prose mt-1 font-normal text-sm leading-6 text-gray-600 dark:text-gray-400" data-component-part="card-content">
                    <div className="grow flex flex-col">
                      {description && !learnByExample && <p>{description}</p>}
                      {source && source.length > 0 && <p className="mt-3">
                            {source.map((item, index) => {
      if (source.length == 1) {
        return <>Open the <a href={item}>Rive file</a>.</>;
      }
      if (index == 0) {
        return <>Open <a href={item}>Rive file 1</a></>;
      }
      return <>, <a href={item}>file {index + 1}</a></>;
    })}
                          </p>}
                    </div>
                    {<div className="mt-6 flex flex-wrap">
                        {runtimesInOrder.map(currentRuntime => {
      if (runtime && currentRuntime !== runtime) return;
      return <RuntimeLink key={currentRuntime} runtime={currentRuntime} link={links[currentRuntime]} />;
    })}
                      </div>}
                  </div>
                </div>
              </div>
            </CardContainer>
          </>;
  })}
    </div>;
};

export const YouTube = ({id, timestamp}) => {
  const videoSrc = timestamp ? `https://www.youtube.com/embed/${id}?start=${timestamp}` : `https://www.youtube.com/embed/${id}`;
  return <iframe width="100%" height="400" src={videoSrc} title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen />;
};

Before engaging with the runtime data binding APIs, it is important to familiarize yourself with the core concepts presented in the [Overview](/editor/data-binding/overview).

<Demos examples={["quickStart", "dataBindingQuickStart"]} runtime="reactNative" />

# View Models

View models describe a set of properties, but cannot themselves be used to get or set values - that is the role of [view model instances](#view-model-instances).

To begin, we need to get a reference to a particular view model. This can be done either by index, by name, or the default for a given artboard, and is done from the Rive file. The default option refers to the view model assigned to an artboard by the dropdown in the editor.

<Tabs>
  <Tab title="New Runtime (Recommended)">
    ```tsx theme={null}
    import { useRiveFile } from '@rive-app/react-native';

    const { riveFile } = useRiveFile(require('./my_file.riv'));

    // Get reference by name
    const namedVM = await riveFile?.viewModelByNameAsync('My View Model');

    // Get all view model names
    const vmNames = await riveFile?.getViewModelNamesAsync(); // ['My View Model', ...]

    // Get reference to the default artboard view model
    const defaultVM = await riveFile?.defaultArtboardViewModelAsync();
    ```
  </Tab>

  <Tab title="Legacy Runtime">
    <Info>
      Creating a view model object is only supported in the new React Native runtime.
    </Info>
  </Tab>
</Tabs>

# View Model Instances

Once we have a reference to a view model, it can be used to create an instance. When creating an instance, you have four options:

1. Create a blank instance - Fill the properties of the created instance with default values as follows:

   | Type              | Value           |
   | ----------------- | --------------- |
   | Number            | 0               |
   | String            | Empty string    |
   | Boolean           | False           |
   | Color             | 0xFF000000      |
   | Trigger           | Untriggered     |
   | Enum              | The first value |
   | Image             | No image        |
   | Artboard          | No artboard     |
   | List              | Empty list      |
   | Nested view model | Null            |

2. Create the default instance - Use the instance labelled "Default" in the editor. Usually this is the one a designer intends as the primary one to be used at runtime.

3. Create by index - Using the order returned when iterating over all available instances. Useful when creating multiple instances by iteration.

4. Create by name - Use the editor's instance name. Useful when creating a specific instance.

<Note>
  In some samples, due to the wordiness of "view model instance", we use the abbreviation "VMI", as well as "VM" for "view model".
</Note>

<Tabs>
  <Tab title="New Runtime (Recommended)">
    Use the `useViewModelInstance` hook to create a view model instance. You can pass a `RiveFile`, `ViewModel`, or `RiveViewRef` as the source.

    ```tsx theme={null}
    import { useRiveFile, useViewModelInstance, RiveView } from '@rive-app/react-native';

    const { riveFile } = useRiveFile(require('./my_file.riv'));

    // From RiveFile — default artboard's ViewModel, default instance
    const { instance } = useViewModelInstance(riveFile);

    // Specify artboard or ViewModel name (mutually exclusive)
    const { instance } = useViewModelInstance(riveFile, { artboardName: 'MainArtboard' });
    const { instance } = useViewModelInstance(riveFile, { viewModelName: 'Settings' });

    // instanceName can be combined with any of the above to pick a specific instance
    const { instance } = useViewModelInstance(riveFile, { instanceName: 'PersonInstance' });
    const { instance } = useViewModelInstance(riveFile, { viewModelName: 'Settings', instanceName: 'UserSettings' });

    // From a ViewModel object
    const viewModel = riveFile?.viewModelByName('My View Model');
    const { instance: namedInstance } = useViewModelInstance(viewModel, { name: 'My Instance' });
    const { instance: newInstance } = useViewModelInstance(viewModel, { useNew: true });

    // With required: true (throws if null, use with Error Boundary)
    const { instance } = useViewModelInstance(riveFile, { required: true });

    // With onInit to set initial values synchronously
    const { instance } = useViewModelInstance(riveFile, {
        onInit: (vmi) => {
            vmi.numberProperty('health')?.set(100);
        },
    });

    return (
        <RiveView file={riveFile} dataBind={instance} />
    );
    ```

    You can also get the auto-bound instance from a `RiveViewRef`:

    ```tsx theme={null}
    import { useRive, useViewModelInstance } from '@rive-app/react-native';

    const { riveViewRef, setHybridRef } = useRive();
    const { instance } = useViewModelInstance(riveViewRef);
    ```
  </Tab>

  <Tab title="Legacy Runtime">
    You can bind a view model instance to a Rive component by passing in a `dataBinding` prop to the Rive component.

    The `dataBinding` prop accepts a `DataBindBy` type, which can be one of the following:

    ```typescript theme={null}
    export type DataBindBy =
        | { type: 'autobind'; value: boolean }
        | { type: 'index'; value: number }
        | { type: 'name'; value: string }
        | { type: 'empty' };

    export const AutoBind = (value: boolean): DataBindBy => ({
        type: 'autobind',
        value,
    });
    export const BindByIndex = (value: number): DataBindBy => ({
        type: 'index',
        value,
    });
    export const BindByName = (value: string): DataBindBy => ({
        type: 'name',
        value,
    });
    export const BindEmpty = (): DataBindBy => ({ type: 'empty' });
    ```

    Example usage:

    ```typescript {7,8,9,10} theme={null}
    const [setRiveRef, riveRef] = useRive();

    return (
        <Rive
            ref={setRiveRef}
            autoplay={true}
            dataBinding={AutoBind(true)} // default: `AutoBind(false)`
            // dataBinding={BindByIndex(0)}
            // dataBinding={BindByName('SomeName')}
            // dataBinding={BindEmpty()}
            stateMachineName={'State Machine 1'}
            resourceName={'rewards'}
        />
    );
    ```

    You can listen to errors by passing in the `onError={(riveError: RNRiveError)` prop to the Rive component.
    The `riveError` object contains the error type and message, and you can filter out for `RNRiveErrorType.DataBindingError`:

    ```typescript theme={null}
    onError={(riveError: RNRiveError) => {
        switch (riveError.type) {
            case RNRiveErrorType.DataBindingError: {
            console.error(`${riveError.message}`);
            return;
            }
            default:
            console.error('Unhandled error');
            return;
        }
    }}
    ```
  </Tab>
</Tabs>

### Binding

The created instance can then be assigned to a state machine or artboard. This establishes the bindings set up at edit time.

It is preferred to assign to a state machine, as this will automatically apply the instance to the artboard as well. Only assign to an artboard if you are not using a state machine, i.e. your file is static or uses linear animations.

<Note>
  The initial values of the instance are not applied to their bound elements until the state machine or artboard advances.
</Note>

<Tabs>
  <Tab title="New Runtime (Recommended)">
    For React Native, no additional steps are needed to bind the view model instance to the Rive component. Pass the instance to the `dataBind` prop on `RiveView`:

    ```tsx theme={null}
    import { RiveView, useRiveFile, useViewModelInstance } from '@rive-app/react-native';

    const { riveFile } = useRiveFile(require('./my_file.riv'));
    const { instance } = useViewModelInstance(riveFile);

    return (
        <RiveView
            file={riveFile}
            dataBind={instance}
        />
    );
    ```
  </Tab>

  <Tab title="Legacy Runtime">
    For React Native, no additional steps are needed to bind the view model instance to the Rive component. The `dataBinding` prop handles this automatically.
  </Tab>
</Tabs>

### Auto-Binding

Alternatively, you may prefer to use auto-binding. This will automatically bind the default view model of the artboard using the default instance to both the state machine and the artboard. The default view model is the one selected on the artboard in the editor dropdown. The default instance is the one marked "Default" in the editor.

<Tabs>
  <Tab title="New Runtime (Recommended)">
    Auto-binding is available through the `DataBindMode` enum. You can pass `DataBindMode.Auto` to the `dataBind` prop:

    ```tsx theme={null}
    import { RiveView, useRiveFile, DataBindMode } from '@rive-app/react-native';

    const { riveFile } = useRiveFile(require('./my_file.riv'));

    return (
        <RiveView
            file={riveFile}
            dataBind={DataBindMode.Auto}
            autoPlay={true}
        />
    );
    ```

    You can also bind by name:

    ```tsx theme={null}
    <RiveView
        file={riveFile}
        dataBind={{ byName: 'My Instance' }}
        autoPlay={true}
    />
    ```

    Or bind a specific instance:

    ```tsx theme={null}
    const { instance } = useViewModelInstance(riveFile);
    <RiveView
        file={riveFile}
        dataBind={instance}
        autoPlay={true}
    />
    ```
  </Tab>

  <Tab title="Legacy Runtime">
    The default value for the `dataBinding` prop is `AutoBind(false)`, which means auto-binding is disabled by default.

    To enable auto-binding, set the `dataBinding` prop to `AutoBind(true)`.

    ```typescript {7} theme={null}
    const [setRiveRef, riveRef] = useRive();

    return (
        <Rive
            ref={setRiveRef}
            autoplay={true}
            dataBinding={AutoBind(true)} // default: `AutoBind(false)`
            stateMachineName={'State Machine 1'}
            resourceName={'rewards'}
        />
    );
    ```
  </Tab>
</Tabs>

# Properties

A property is a value that can be read, set, or observed on a view model instance. Properties can be of the following types:

| Type                   | Supported |
| ---------------------- | --------- |
| Floating point numbers | ✅         |
| Booleans               | ✅         |
| Triggers               | ✅         |
| Strings                | ✅         |
| Enumerations           | ✅         |
| Colors                 | ✅         |
| Nested View Models     | ✅         |
| Lists                  | ✅         |
| Images                 | ✅         |
| Artboards              | ✅         |

For more information on version compatibility, see the [Feature Support](/feature-support) page.

### Listing Properties

Property descriptors can be inspected on a view model to discover at runtime which are available. These are not the mutable properties themselves though - once again those are on instances. These descriptors have a type and name.

<Tabs>
  <Tab title="New Runtime (Recommended)">
    <Note>Coming soon</Note>
  </Tab>

  <Tab title="Legacy Runtime">
    <Warning>
      The properties API is not supported on the legacy runtime.
    </Warning>
  </Tab>
</Tabs>

### Reading and Writing Properties

References to these properties can be retrieved by name or path.

Some properties are mutable and have getters, setters, and observer operations for their values. Getting or observing the value will retrieve the latest value set on that property's binding, as of the last state machine or artboard advance. Setting the value will update the value and all of its bound elements.

<Note>
  After setting a property's value, the changes will not apply to their bound elements until the state machine or artboard advances.
</Note>

<Tabs>
  <Tab title="New Runtime (Recommended)">
    Use the specific hooks for each property type to get and set property values:

    * `useRiveBoolean`: Read/write boolean properties
    * `useRiveString`: Read/write string properties
    * `useRiveNumber`: Read/write number properties
    * `useRiveColor`: Read/write color properties with hex string or RGBA support
    * `useRiveEnum`: Read/write enum properties
    * `useRiveTrigger`: Fire trigger events with optional callbacks

    These hooks return the current `value`, a setter function (`setValue` or `trigger`), and an `error` if the property is not found.

    <Note>
      The `setValue` function allows you to pass a function that receives the previous value, similar to React's `setState` pattern. This is useful when you need to update a value based on its current state:

      ```tsx theme={null}
      setValue((v) => (v ?? 0) + 5)
      ```
    </Note>

    ```tsx theme={null}
    import {
        useRiveFile,
        useViewModelInstance,
        useRiveBoolean,
        useRiveString,
        useRiveNumber,
        useRiveColor,
        useRiveEnum,
        useRiveTrigger,
        RiveView
    } from '@rive-app/react-native';

    const { riveFile } = useRiveFile(require('./my_file.riv'));
    const { instance } = useViewModelInstance(riveFile);

    // Boolean
    const { value: isActive, setValue: setIsActive, error: boolError } = useRiveBoolean(
        'isToggleOn',
        instance
    );
    // Set: setIsActive(true);

    // String
    const { value: userName, setValue: setUserName, error: stringError } = useRiveString(
        'user/name',
        instance
    );
    // Set: setUserName('Rive');

    // Number
    const { value: score, setValue: setScore, error: numberError } = useRiveNumber(
        'levelScore',
        instance
    );
    // Set: setScore(100);

    // Color (accepts hex string or RiveColor object)
    const { value: themeColor, setValue: setThemeColor, error: colorError } = useRiveColor(
        'ui/themeColor',
        instance
    );
    // Set: setThemeColor('#FF0000FF'); // hex string
    // Or: setThemeColor({ r: 255, g: 0, b: 0, a: 255 }); // RGBA object

    // Enum
    const { value: status, setValue: setStatus, error: enumError } = useRiveEnum(
        'appStatus',
        instance
    );
    // Set: setStatus('loading');

    // Trigger (No value, just a trigger function)
    const { trigger: playEffect, error: triggerError } = useRiveTrigger(
        'playButtonEffect',
        instance,
        {
            // Optional callback to be called when the trigger is fired
            onTrigger: () => {
                console.log('Trigger Fired!');
            }
        }
    );
    // Trigger: playEffect();

    return (
        <RiveView
            file={riveFile}
            dataBind={instance}
            autoPlay={true}
        />
    );
    ```

    The `value` returned by each hook will update automatically when the property changes in the Rive graphic.
  </Tab>

  <Tab title="Legacy Runtime">
    The following data binding methods are exposed on the `RiveRef` object.

    ```typescript theme={null}
    setBoolean: (path: string, value: boolean) => void;
    setString: (path: string, value: string) => void;
    setNumber: (path: string, value: number) => void;
    setColor: (path: string, color: RiveRGBA | string) => void;
    setEnum: (path: string, value: string) => void;
    trigger: (path: string) => void;
    ```

    <Note>
      The color property can be set using either a `RiveRGBA` object or a hex string. The hex string should be in the format
      `#RRGGBBAA`, where `RR`, `GG`, `BB`, and `AA` are two-digit hexadecimal values representing the red, green, blue, and
      alpha channels, respectively.

      ```js theme={null}
      type RiveRGBA = { r: number; g: number; b: number; a: number };
      ```
    </Note>

    Example usage:

    ```typescript theme={null}
    const [setRiveRef, riveRef] = useRive();
    const setBoolean = () => {
        if (riveRef) {
            riveRef.setBoolean('My Boolean Property', true);
        }
    };
    const setString = () => {
        if (riveRef) {
            riveRef.current.setString('My String Property', 'Hello, Rive');
        }
    };
    const setNumber = () => {
        if (riveRef) {
            riveRef.current.setNumber('My Number Property', 10);
        }
    };
    const setColor = () => {
        if (riveRef) {
            riveRef.setColor('My Color Property', { r: 255, g: 0, b: 0, a: 1 });
            // or
            riveRef.setColor('My Color Property', '#00FF00FF');
        }
    };
    const setEnum = () => {
        if (riveRef) {
            riveRef.setEnum('My Enum Property', 'Option 1');
        }
    };
    const trigger = () => {
        if (riveRef) {
            riveRef.trigger('My Trigger Property');
        }
    };
    ```
  </Tab>
</Tabs>

### Nested Property Paths

View models can have properties of type view model, allowing for arbitrary nesting. You can chain property calls on each instance starting from the root until you get to the property of interest. Alternatively, you can do this through a path parameter, which is similar to a URI in that it is a forward slash delimited list of property names ending in the name of the property of interest.

<Tabs>
  <Tab title="New Runtime (Recommended)">
    Access nested properties by providing the full path (separated by `/`) as the first argument to the property hooks.

    ```tsx theme={null}
    import { useRiveString, useRiveNumber, useRiveFile, useViewModelInstance } from '@rive-app/react-native';

    const { riveFile } = useRiveFile(require('./my_file.riv'));
    const { instance } = useViewModelInstance(riveFile);

    // Accessing 'settings/theme/name' (String)
    const { value: themeName, setValue: setThemeName } = useRiveString(
        'settings/theme/name',
        instance
    );

    // Accessing 'settings/volume' (Number)
    const { value: volume, setValue: setVolume } = useRiveNumber(
        'settings/volume',
        instance
    );

    console.log('Current theme:', themeName);
    // setThemeName('Dark Mode');
    // setVolume(80);
    ```

    <Info>
      The Rive React Native runtime does not yet support accessing a ViewModel property directly, to be able to do the chain notation.
    </Info>
  </Tab>

  <Tab title="Legacy Runtime">
    <Warning>
      The Rive React Native runtime does not support accessing nested properties using the chain notation.
      But you can access nested properties using the path notation.
    </Warning>

    ```js theme={null}
    const [setRiveRef, riveRef] = useRive();
    const nestedNumberByPath = useRiveNumber(riveRef, 'My Nested View Model/My Second Nested VM/My Nested Number');
    useEffect(() => {
        if (nestedNumberByPath) {
            nestedNumberByPath.setValue(10);
        }
    }, [nestedNumberByPath]);
    ```
  </Tab>
</Tabs>

### Observability

You can observe changes over time to property values, either by using listeners or a platform equivalent method. Once observed, you will be notified when the property changes are applied by a state machine advance, whether that is a new value that has been explicitly set or if the value was updated as a result of a binding.

<Tabs>
  <Tab title="New Runtime (Recommended)">
    Values are observed automatically through hooks. When a property's value changes within the Rive instance (either because you set it via a hook or due to an internal binding), the `value` returned by the corresponding hook updates. This state change triggers a re-render of your React component, allowing you to react to the new value.

    For Triggers, you can provide an `onTrigger` callback directly to the `useRiveTrigger` hook, which fires when the trigger is activated in the Rive instance.

    ```tsx theme={null}
    import {
        useRiveFile,
        useViewModelInstance,
        useRiveBoolean,
        useRiveString,
        useRiveNumber,
        useRiveColor,
        useRiveEnum,
        useRiveTrigger,
        useEffect
    } from '@rive-app/react-native';

    const { riveFile } = useRiveFile(require('./my_file.riv'));
    const { instance } = useViewModelInstance(riveFile);

    const { value: boolValue, setValue: setBoolValue } = useRiveBoolean('My Boolean Property', instance);
    const { value: stringValue, setValue: setStringValue } = useRiveString('My String Property', instance);
    const { value: numberValue, setValue: setNumberValue } = useRiveNumber('My Number Property', instance);
    const { value: colorValue, setValue: setColorValue } = useRiveColor('My Color Property', instance);
    const { value: enumValue, setValue: setEnumValue } = useRiveEnum('My Enum Property', instance);
    const { trigger: triggerButton } = useRiveTrigger('My Trigger Property', instance, {
        onTrigger: () => {
            console.log('Trigger fired');
        }
    });

    useEffect(() => {
        if (numberValue !== undefined) {
            console.log('numberValue changed:', numberValue);
        }
    }, [numberValue]);

    const handleButtonPress = () => {
        triggerButton();
    };
    ```

    <Note>
      The `useRiveTrigger` hook returns a `trigger` function that can be called to fire the trigger. This hook accepts an optional `onTrigger` callback in its third parameter that will be executed when the trigger is fired.
    </Note>
  </Tab>

  <Tab title="Legacy Runtime">
    Values are observed through hooks.

    ```typescript theme={null}
    const [setRiveRef, riveRef] = useRive();
    const [boolValue, setBoolValue] = useRiveBoolean(riveRef, 'My Boolean Property');
    const [stringValue, setStringValue] = useRiveString(riveRef, 'My String Property');
    const [numberValue, setNumberValue] = useRiveNumber(riveRef, 'My Number Property');
    const [colorValue, setColorValue] = useRiveColor(riveRef, 'My Color Property');
    const [enumValue, setEnumValue] = useRiveEnum(riveRef, 'My Enum Property');
    const triggerButton = useRiveTrigger(riveRef, 'My Trigger Property', () => {
        console.log('Trigger fired');
    });

    useEffect(() => {
        if (numberValue !== undefined) {
            console.log('numberValue changed:', numberValue);
        }
    }, [numberValue]);

    const handleButtonPress = () => {
        if (triggerButton) {
            triggerButton();
        }
    };
    ```

    <Note>
      The `useRiveTrigger` hook does not return a value, but instead takes a callback function as its third argument.
      This callback will be executed when the trigger is fired.
    </Note>
  </Tab>
</Tabs>

### Images

Image properties let you set and replace raster images at runtime, with each instance of the image managed independently. For example, you could build an avatar creator and dynamically update features — like swapping out a hat — by setting a view model's image property.

<Tabs>
  <Tab title="New Runtime (Recommended)">
    Image properties can be set using the `imageProperty` method on a `ViewModelInstance` and the `RiveImages` utility for loading images.

    ```tsx theme={null}
    import {
        useRive,
        useRiveFile,
        useViewModelInstance,
        RiveView,
        RiveImages,
        type RiveViewRef
    } from '@rive-app/react-native';
    import { useRef } from 'react';

    const { riveViewRef, setHybridRef } = useRive();
    const { riveFile } = useRiveFile(require('./my_file.riv'));
    const { instance } = useViewModelInstance(riveFile);
    const riveViewRef = useRef<RiveViewRef>(undefined);

    const handleLoadImage = async () => {
        if (!riveViewRef) return;

        const vmi = riveViewRef.getViewModelInstance();
        if (!vmi) return;

        const imgProp = vmi.imageProperty('imageValue');
        if (!imgProp) return;

        // Load image from URL
        const riveImage = await RiveImages.loadFromURLAsync(
            'https://picsum.photos/id/372/500/500'
        );
        imgProp.set(riveImage);
        riveViewRef.playIfNeeded();
    };

    return (
        <RiveView
            hybridRef={setHybridRef}
            file={riveFile}
            dataBind={instance}
            autoPlay={true}
        />
    );
    ```

    You can also add listeners to image properties:

    ```tsx theme={null}
    const imgProp = vmi.imageProperty('imageValue');
    if (imgProp) {
        imgProp.addListener(() => {
            console.log('Image property changed!');
        });
    }
    ```

    Other image loading options on `RiveImages`:

    ```ts theme={null}
        /**
        * Load an image from a bundled resource
        * @param resource The resource name (e.g., "image.png")
        * @returns A promise that resolves to the loaded RiveImage
        */
        loadFromResourceAsync(resource: string): Promise<RiveImage>;

        /**
        * Load an image from raw bytes
        * @param bytes The image data as an ArrayBuffer
        * @returns A promise that resolves to the loaded RiveImage
        */
        loadFromBytesAsync(bytes: ArrayBuffer): Promise<RiveImage>;
    ```
  </Tab>

  <Tab title="Legacy Runtime">
    <Warning>
      Image data binding is not supported on the legacy runtime.
    </Warning>
  </Tab>
</Tabs>

### Lists

List properties let you manage a dynamic set of view model instances at runtime. For example, you can build a TODO app where users can add and remove tasks in a scrollable Layout.

See the [Editor section](/editor/data-binding/lists) on creating data bound lists.

A single list property can include different view model types, with each view model tied to its own Component, making it easy to populate a list with a variety of Component instances.

With list properties, you can:

* Add a new view model instance (optionally at an index)
* Remove an existing view model instance (optionally by index)
* Swap two view model instances by index
* Get the size of a list

For more information on list properties, see the [Data Binding List Property](/editor/data-binding/lists#view-model-list-property) editor documentation.

<Tabs>
  <Tab title="New Runtime (Recommended)">
    Use the `useRiveList` hook to manage list properties on view model instances.

    ```tsx theme={null}
    import {
        useRiveFile,
        useViewModelInstance,
        useRiveList,
        RiveView
    } from '@rive-app/react-native';

    const { riveFile } = useRiveFile(require('./my_file.riv'));
    const { instance } = useViewModelInstance(riveFile);

    // Get the list property with manipulation functions
    const {
        length,
        getInstanceAt,
        addInstance,
        addInstanceAt,
        removeInstance,
        removeInstanceAt,
        swap,
        error
    } = useRiveList('todos', instance);

    // Add a new todo item
    const handleAddItem = async () => {
        const todoItemViewModel = await riveFile?.viewModelByNameAsync('TodoItem');
        if (todoItemViewModel) {
            const newTodoItem = await todoItemViewModel.createBlankInstanceAsync();
            if (newTodoItem) {
                // Set some initial values
                newTodoItem.stringProperty('description')?.set('Buy groceries');
                addInstance(newTodoItem);
            }
        }
    };

    // Insert item at specific index
    const handleInsertItem = async () => {
        const todoItemViewModel = await riveFile?.viewModelByNameAsync('TodoItem');
        if (todoItemViewModel) {
            const newTodoItem = await todoItemViewModel.createBlankInstanceAsync();
            if (newTodoItem) {
                addInstanceAt(newTodoItem, 0); // Insert at beginning
            }
        }
    };

    // Remove first item by instance
    const handleRemoveFirst = () => {
        const firstInstance = getInstanceAt(0);
        if (firstInstance) {
            removeInstance(firstInstance);
        }
    };

    // Remove item by index
    const handleRemoveAt = () => {
        if (length > 0) {
            removeInstanceAt(0);
        }
    };

    // Swap two items
    const handleSwap = () => {
        if (length >= 2) {
            swap(0, 1);
        }
    };

    console.log(`List has ${length} items`);

    return (
        <RiveView
            file={riveFile}
            dataBind={instance}
            autoPlay={true}
        />
    );
    ```
  </Tab>

  <Tab title="Legacy Runtime">
    <Warning>
      List data binding is not supported on the legacy runtime.
    </Warning>
  </Tab>
</Tabs>

### Artboards

Artboard properties allows you to swap out entire components at runtime. This is useful for creating modular components that can be reused across different designs or applications, for example:

* Creating a skinning system that supports a large number of variations, such as a character creator where you can swap out different body parts, clothing, and accessories.
* Creating a complex scene that is a composition of various artboards loaded from various different Rive files (drawn to a single canvas/texture/widget).
* Reducing the size (complexity) of a single Rive file by breaking it up into smaller components that can be loaded on demand and swapped in and out as needed.

<Demos examples={["dataBindingArtboards"]} runtime="reactNative" />

<Tabs>
  <Tab title="New Runtime (Recommended)">
    <Info>
      See the [React Native data binding artboards example](https://github.com/rive-app/rive-nitro-react-native/blob/main/example/src/demos/DataBindingArtboardsExample.tsx).
    </Info>

    Artboard properties work with the `BindableArtboard` class. Use `getBindableArtboard` on a `RiveFile` to create a bindable reference, then set it on the artboard property.

    ```typescript theme={null}
    // Get artboard property from view model instance
    const artboardProp = instance.artboardProperty('CharacterArtboard');

    // Create a bindable artboard and set it
    const bindableArtboard = riveFile.getBindableArtboard('Character 1');
    artboardProp?.set(bindableArtboard);
    ```
  </Tab>

  <Tab title="Legacy Runtime">
    <Warning>
      Artboard data binding is not supported on the legacy runtime.
    </Warning>
  </Tab>
</Tabs>

### Enums

Enums properties come in two flavors: system and user-defined. In practice, you will not need to worry about the distinction, but just be aware that system enums are available in any Rive file that binds to an editor-defined enum set, representing options from the editor's dropdowns, where user-defined enums are those defined by a designer in the editor.

Enums are string typed. The Rive file contains a list of enums. Each enum in turn has a name and a list of strings.

<Tabs>
  <Tab title="New Runtime (Recommended)">
    You can access enum properties using the `useRiveEnum` hook. The hook returns the current value and a setter function.

    ```tsx theme={null}
    import {
        useRiveFile,
        useViewModelInstance,
        useRiveEnum,
        RiveView
    } from '@rive-app/react-native';

    const { riveFile } = useRiveFile(require('./my_file.riv'));
    const { instance } = useViewModelInstance(riveFile);

    const { value: category, setValue: setCategory, error } = useRiveEnum(
        'category',
        instance
    );

    // Set enum value
    setCategory('option_name');

    return (
        <RiveView
            file={riveFile}
            dataBind={instance}
            autoPlay={true}
        />
    );
    ```

    <Note>
      Retrieving the list of all enums in the file, or accessing all possible values on an Enum, is not yet available.
    </Note>
  </Tab>

  <Tab title="Legacy Runtime">
    <Warning>
      Retrieving the list of enums is not supported on the legacy API.
    </Warning>
  </Tab>
</Tabs>

# Examples

<Tabs>
  <Tab title="New Runtime (Recommended)">
    See the [example app](https://github.com/rive-app/rive-nitro-react-native/tree/main/example) for data binding demos with the new runtime.
  </Tab>

  <Tab title="Legacy Runtime">
    See the [Data Binding view](https://github.com/rive-app/rive-react-native/blob/main/example/app/\(examples\)/DataBinding.tsx) in the Example app for a demo.
  </Tab>
</Tabs>
