> ## 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={["dataBindingQuickStart"]} runtime="android" />

# 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="Compose">
    Unlike other runtimes, view models do not exist as a separate object in the Compose API. Instead, they are represented as a `ViewModelSource` sealed class that forms half of a builder pattern used to create view model instances. See [View Model Instances](#view-model-instances) for details on the other half - creating instances.

    ```kotlin theme={null}
    // Named source
    val vmSource = ViewModelSource.Named("My View Model")
    // Default for artboard source
    val vmSource = ViewModelSource.DefaultForArtboard(artboard)
    ```
  </Tab>

  <Tab title="Legacy">
    ```kotlin theme={null}
    // `view` of type RiveAnimationView
    view.setRiveResource(R.raw.my_rive_file)
    val file = view.controller.file!!

    // Get reference by name
    val vm = file.getViewModelByName("My View Model")

    // Get reference by index
    for (i in 0 until file.viewModelCount) {
        val indexedVM = file.getViewModelByIndex(i)
    }

    // Get reference to the default view model
    val defaultVM = file.defaultViewModelForArtboard(view.controller.activeArtboard!!)
    ```
  </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="Compose">
    See [View Models](#view-models) for how to get a `ViewModelSource` to use below. With that, you can use the builder pattern to create a `ViewModelInstanceSource`, the second half. That source can then be passed to `rememberViewModelInstance` to create and remember the instance for the lifetime of the composition.

    ```kotlin theme={null}
    // From previous section
    val vmSource = ViewModelSource.Named("My View Model")

    // Blank instance source
    val vmiSourceBlank = ViewModelInstanceSource.Blank(vmSource)
    // or
    val vmiSourceBlank = vmSource.blankInstance()

    // Default instance source
    val vmiSourceDefault = ViewModelInstanceSource.Default(vmSource)
    // or
    val vmiSourceDefault = vmSource.defaultInstance()

    // Named instance source
    val vmiSourceNamed = ViewModelInstanceSource.Named(vmSource, "My Instance")
    // or
    val vmiSourceNamed = vmSource.namedInstance("My Instance")

    // The completed source can now be used along with the Rive file to create and remember the instance
    val viewModelInstance = rememberViewModelInstance(riveFile, vmiSourceNamed)
    ```

    Additionally, you can reference a nested view model instance from within a parent instance using the `Reference` variant.

    ```kotlin theme={null}
    val myVMI = rememberViewModelInstance(riveFile, mySource)
    val referenceSource = ViewModelInstanceSource.Reference(myVMI, "Path/To/Nested VMI")
    val nestedVMI = rememberViewModelInstance(riveFile, referenceSource)
    ```
  </Tab>

  <Tab title="Legacy">
    ```kotlin theme={null}
    val vm = view.controller.file?.getViewModelByName("My View Model")!!

    // Create blank
    val vmiBlank = vm.createBlankInstance()

    // Create default
    val vmiDefault = vm.createDefaultInstance()

    // Create by index
    for (i in 0 until vm.instanceCount) {
        val vmiIndexed = vm.createInstanceFromIndex(i)
    }

    // Create by name
    val vmiNamed = vm.createInstanceFromName("My Instance")
    ```
  </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="Compose">
    See the [Compose data binding example](https://github.com/rive-app/rive-android/blob/master/app/src/main/java/app/rive/runtime/example/ComposeDataBindingActivity.kt).

    Binding to the state machine happens automatically when the `ViewModelInstance` is passed to the `Rive` composable.

    ```kotlin {6} theme={null}
    val vmiSource = ViewModelSource.Named("My View Model").namedInstance("My Instance")
    val vmi = rememberViewModelInstance(riveFile, vmiSource)

    Rive(
        riveFile,
        viewModelInstance = vmi
    )
    ```
  </Tab>

  <Tab title="Legacy">
    See the [Legacy data binding example](https://github.com/rive-app/rive-android/blob/master/app/src/main/java/app/rive/runtime/example/LegacyDataBindingActivity.kt).

    ```kotlin theme={null}
    view.setRiveResource(
        R.raw.my_rive_file,
        artboardName = "My Artboard",
    )

    val vm = view.controller.file?.getViewModelByName("My View Model")!!
    val vmi = vm.createInstanceFromName("My Instance")

    // Apply the instance to the state machine (preferred)
    view.controller.stateMachines.first().viewModelInstance = vmi

    // Alternatively, apply the instance to the artboard
    view.controller.activeArtboard?.viewModelInstance = vmi
    ```
  </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="Compose">
    Auto-binding does not exist in the Compose API due to the nature of composables. Since they are functions, it is difficult to get values out of them as compared to classes. Callbacks would require a null placeholder to remember the value before it has fired which creates more overhead than supplying the instance directly.

    The equivalent is to create a view model instance with no source. This will internally create the default artboard, the default view model for that artboard, and the default instance for that view model. You can then pass that into the `Rive` composable.

    ```kotlin theme={null}
    val vmi = rememberViewModelInstance(riveFile)
    Rive(
        riveFile,
        viewModelInstance = vmi,
    )
    ```
  </Tab>

  <Tab title="Legacy">
    ```kotlin {3} theme={null}
    view.setRiveResource(
        R.raw.my_rive_file,
        autoBind = true,
    )
    ```
  </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="Compose">
    Getting view model properties is a suspend operation, so it needs to be called from a coroutine scope such as `LaunchedEffect`.

    ```kotlin theme={null}
    LaunchedEffect(riveFile) {
        riveFile.getViewModelProperties("My View Model").forEach { property ->
            Log.d("My Tag", "Property Name: ${property.name}, Type: ${property.type}")
        }
    }
    ```
  </Tab>

  <Tab title="Legacy">
    ```kotlin theme={null}
    val vm = view.controller.file?.getViewModelByName("My View Model")!!

    // A list of properties
    val properties = vm.properties
    assertContains(
        properties,
        ViewModel.Property(ViewModel.PropertyDataType.NUMBER, "My Number Property")
    )
    ```
  </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="Compose">
    ### Writing Values

    The Compose API does not have explicit property objects. Instead, property values are set on the `ViewModelInstance` directly using methods which take their path.

    ```kotlin theme={null}
    val vmi = rememberViewModelInstance(...)
    vmi.setNumberProperty("Path/To/Property", 10f)
    ```

    ### Reading  Values

    Values are read throw a Kotlin [`Flow`](https://kotlinlang.org/docs/flow.html) which emits the latest value whenever it changes. You can collect this flow in a `LaunchedEffect` or convert it to a `State` using `collectAsState()` (or use `collectAsStateWithLifecycle()` to only collect during certain lifecycle states).

    To get the latest value once without observing, you can use the terminal `first()` operator.

    ```kotlin theme={null}
    val vmi = rememberViewModelInstance(...)
    // Collect as State
    val numberValue by vmi.numberPropertyFlow("Path/To/Property").collectAsState(initial = 0f)

    Text(text = "Number value: $numberValue")

    // Or collect
    LaunchedEffect(vmi) {
        vmi.numberPropertyFlow("Path/To/Property").collect { value ->
            Log.d("Rive", "Number value changed: $value")
        }

        // Or get once
        val numberValue = vmi.numberPropertyFlow("Path/To/Property").first()
        Log.d("Rive", "Current number value: $numberValue")
    }
    ```
  </Tab>

  <Tab title="Legacy">
    ```kotlin theme={null}
    val vm = view.controller.file?.getViewModelByName("My View Model")!!
    val vmi = vm.createInstanceFromName("My Instance")

    val numberProperty = vmi.getNumberProperty("My Number Property")
    // Get
    val numberValue = numberProperty.value
    // Set
    numberProperty.value = 10f
    ```
  </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="Compose">
    ```kotlin theme={null}
    val parent = rememberViewModelInstance(riveFile, ViewModelSource.Named("Parent VM").namedInstance("Parent"))

    // Using references
    val child = rememberViewModelInstance(riveFile, ViewModelInstanceSource.Reference(parent, "Child"))
    val nestedNumber = child.numberPropertyFlow("My Nested Number").collectAsState(0f)

    // Or using paths
    val nestedNumber = parent.numberPropertyFlow("Child/My Nested Number").collectAsState(0f)
    ```
  </Tab>

  <Tab title="Legacy">
    ```kotlin theme={null}
    val vm = view.controller.file?.getViewModelByName("My View Model")!!
    val vmi = vm.createInstanceFromName("My Instance")

    val nestedNumberByChain = vmi
        .getInstanceProperty("My Nested View Model")
        .getInstanceProperty("My Second Nested VM")
        .getNumberProperty("My Nested Number")

    val nestedNumberByPath = vmi
        .getNumberProperty("My Nested View Model/My Second Nested VM/My Nested Number")
    ```
  </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="Compose">
    Observability is the default behavior when using the Compose API with Kotlin Flows. When you collect a property's flow, you will receive updates whenever the property's value changes.

    ```kotlin theme={null}
    val vmi = rememberViewModelInstance(...)
    val numberPropertyFlow = vmi.numberPropertyFlow("My Number Property").collectAsState(0f)
    ```
  </Tab>

  <Tab title="Legacy">
    ```kotlin theme={null}
    val vm = view.controller.file?.getViewModelByName("My View Model")!!
    val vmi = vm.createInstanceFromName("My Instance")

    val numberProperty = vmi.getNumberProperty("My Number Property")
    // Observe
    lifecycleScope.launch {
        numberProperty.valueFlow.collect { value ->
            Log.i("MyActivity", "Value: $value")
        }
    }
    // Or collect in Compose
    val numberValue by numberProperty.valueFlow.collectAsState(0f) // 0 as the initial value while waiting for the first value
    ```
  </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.

<Demos examples={['dataBindingImages']} runtime="android" />

<Tabs>
  <Tab title="Compose">
    See the [Compose data binding images example](https://github.com/rive-app/rive-android/blob/master/app/src/main/java/app/rive/runtime/example/ComposeImageBindingActivity.kt).

    To set an image property, you need an `ImageAsset`, which can be created from `rememberImage` using a byte array. The below example loads from raw resources into a `Result` for convenience, but you should use the pattern most appropriate for your app.

    ```kotlin theme={null}
    val imageBytes by produceState<Result<ByteArray>>(Result.Loading) {
        value = withContext(Dispatchers.IO) {
            context.resources.openRawResource(R.raw.my_image)
                .use { Result.Success(it.readBytes()) }
        }
    }

    // `andThen` maps over the Result to only call the lambda if it's a Success, propagating Failure and Loading otherwise.
    val image = imageBytes.andThen { bytes ->
        rememberImage(riveWorker, bytes)
    }

    // Or combine into one statement
    val image = produceState<Result<ByteArray>>(Result.Loading) {
        value = withContext(Dispatchers.IO) {
            context.resources.openRawResource(R.raw.my_image)
                .use { Result.Success(it.readBytes()) }
        }
    }.value.andThen { bytes ->
        rememberImage(riveWorker, bytes)
    }

    val vmi = rememberViewModelInstance(riveFile, ViewModelSource.Named("My View Model").defaultInstance())
    LaunchedEffect(vmi, image) {
        when(image) {
            is Result.Failure -> { /* Handle failure to load image */ }
            is Result.Loading -> { /* Handle loading state if needed */ }
            is Result.Success -> {
                // Set the image property value
                vmi.setImage("Image property", image.value)
            }
        }
    }
    ```

    If you want to gate the presentation of your Rive content until the image is loaded and only if both are successful, you can use the `zip` convenience function to combine multiple `Result` objects together.

    ```kotlin theme={null}
    val fileAndImage = riveFile.zip(image)

    when (fileAndImage) {
        is Result.Failure -> { /* Handle failure to load file or image */ }
        is Result.Loading -> { /* Handle loading state if needed */ }
        is Result.Success -> {
            val (riveFile, image) = fileAndImage.value
            // Both riveFile and image are loaded successfully here
            // You can now present your Rive content and set the image property
        }
    }
    ```

    For more information on image assets, see [Loading Assets](/runtimes/android/loading-assets).
  </Tab>

  <Tab title="Legacy">
    ```kotlin theme={null}
    // Load image from the assets folder.
    val imageBytes = context.resources.openRawResource(R.raw.my_image).use { stream ->
      stream.readBytes()
    }

    val vmi = it.stateMachines.first().viewModelInstance!!

    // Replace image property in view model instance with new image.
    val riveImage = RiveRenderImage.fromEncoded(imageBytes)
    vmi.getImageProperty("Image property").set(riveImage)
    ```
  </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.

<Demos examples={['dataBindingLists']} runtime="android" />

<Tabs>
  <Tab title="Compose">
    See the [Compose data binding lists example](https://github.com/rive-app/rive-android/blob/master/app/src/main/java/app/rive/runtime/example/ComposeListActivity.kt).

    ```kotlin theme={null}
    val mainVMI = rememberViewModelInstance(riveFile)
    val newListItem = rememberViewModelInstance(riveFile, ViewModelSource.Named("My Item VM").namedInstance("My List Item"))
    LaunchedEffect(mainVMI, newListItem) {
        val listProperty = "My List"

        // Add new item to the end of the list
        mainVMI.appendToList(listProperty, newListItem)
        // Insert new item at index 0
        mainVMI.insertToListAtIndex(listProperty, 0, newListItem)

        // Swap items at index 0 and 1
        mainVMI.swapListItems(listProperty, 0, 1)

        // Remove specific instance
        mainVMI.removeFromList(listProperty, newListItem)
        // Remove item at index 0
        mainVMI.removeFromListAtIndex(listProperty, 0)
    }
    ```

    Due to the dynamic nature of lists, you may need to create items within a coroutine rather than ahead of time with `rememberViewModelInstance`. Be aware that adding the same instance multiple times to a list will cause them all to share state, which may not be the desired behavior. Use the following pattern to create new instances as needed.

    ```kotlin theme={null}
    val mainVMI = rememberViewModelInstance(riveFile)
    LaunchedEffect(mainVMI) {
        val listProperty = "My List"
        // ⚠️ This must be `close`d, which is done here through `AutoCloseable.use`.
        ViewModelInstance.fromFile(
            riveFile,
            ViewModelSource.Named("My Item VM").defaultInstance()
        ).use { item ->
            mainVMI.insertToListAtIndex(listProperty, 0, item)
        }
    }
    ```
  </Tab>

  <Tab title="Legacy">
    ```kotlin theme={null}
    // Acquire the default view model instance and the list property.
    val vmi = animationView.file!!.firstArtboard.viewModelInstance!!
    val listProperty = vmi.getListProperty("list")

    // Create a view model instance for "First" and "Second" and add them to the list.
    val firstInstance = animationView.file!!.getViewModelByName("My Item VM").createInstanceFromName("First")
    listProperty.add(firstInstance)

    val secondInstance = animationView.file!!.getViewModelByName("My Item VM").createInstanceFromName("Second")
    listProperty.add(secondInstance)

    // Swap the two items in the list.
    listProperty.swap(0, 1)

    // Remove both items from the list.
    listProperty.remove(firstInstance)
    listProperty.removeAt(0)
    ```
  </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="android" />

<Tabs>
  <Tab title="Compose">
    See the [Compose data binding artboards example](https://github.com/rive-app/rive-android/blob/master/app/src/main/java/app/rive/runtime/example/ComposeArtboardBindingActivity.kt).

    ```kotlin theme={null}
    val vmi = rememberViewModelInstance(mainFile)
    val artboard = rememberArtboard(mainFile, "My Artboard")

    LaunchedEffect(vmi, artboard) {
        vmi.setArtboard("My Artboard Property", artboard)
    }
    ```
  </Tab>

  <Tab title="Legacy">
    ```kotlin theme={null}
    // Acquire the default view model instance and the artboard property.
    val vmi = animationView.file!!.firstArtboard.viewModelInstance!!
    val artboardProperty = vmi.getArtboardProperty("My Artboard Property")

    // Set artboard from same file.
    val localArtboard = animationView.file!!.getArtboard("My Artboard")
    artboardProperty.set(localArtboard)

    // Load external file if needed
    val externalFile = File.load(context.assets, "external_file.riv")

    // Set artboard from external file.
    val externalArtboard = externalFile.getArtboard("My External Artboard")
    artboardProperty.set(externalArtboard)

    // Clean up external file when done
    externalFile.dispose()
    ```

    You can also create a bindable artboard with a view model instance to control its state.

    ```kotlin theme={null}
    // Create the view model instance for the child artboard.
    val childVmi = childFile.getViewModelByName("ChildVM").createBlankInstance()
    val bindableArtboard = childFile.createBindableArtboardByName("Child", childVmi)

    // Get the artboard property from the main artboard.
    val vmi = rive.file!!.firstArtboard.viewModelInstance!!
    val artboardProperty = vmi.getArtboardProperty("Artboard property")

    // Set the bound artboard VMIs state.
    childVmi.getNumberProperty("rotation").value = 90f

    // Set the bound artboard on the main artboard.
    artboardProperty.set(bindableArtboard)

    // Release the reference we hold from creation.
    bindableArtboard.release() 
    ```
  </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="Compose">
    ```kotlin theme={null}
    LaunchedEffect(riveFile) {
        val enums = riveFile.getEnums()
        Log.i("RiveEnums", "First enum name: ${enums[0].name}")
    }
    ```
  </Tab>

  <Tab title="Legacy">
    ```kotlin theme={null}
    val enums = view.controller.file?.enums!!

    val firstEnumName = enums[0].name
    val firstEnumFirstValue = enums[0].values[0]
    ```
  </Tab>
</Tabs>

# Examples

<Tabs>
  <Tab title="Compose">
    See the following examples:

    * [Data Binding Overview](https://github.com/rive-app/rive-android/blob/master/app/src/main/java/app/rive/runtime/example/ComposeDataBindingActivity.kt)
    * [Data Binding Images](https://github.com/rive-app/rive-android/blob/master/app/src/main/java/app/rive/runtime/example/ComposeImageBindingActivity.kt)
    * [Data Binding Artboards](https://github.com/rive-app/rive-android/blob/master/app/src/main/java/app/rive/runtime/example/ComposeArtboardBindingActivity.kt)
    * [Data Binding Lists](https://github.com/rive-app/rive-android/blob/master/app/src/main/java/app/rive/runtime/example/ComposeListActivity.kt)
  </Tab>

  <Tab title="Legacy">
    See the [data binding overview example](https://github.com/rive-app/rive-android/blob/master/app/src/main/java/app/rive/runtime/example/LegacyDataBindingActivity.kt).
  </Tab>
</Tabs>
