Access to XAML controls in a React Native for Windows application
Published: 2023-10-31 10:08:32

---
title: Access to XAML controls in a React Native for Windows application
published: true
date: 2022-05-19 15:07:27 UTC
tags: 
canonical_url: 
---

When you build a Windows application using React Native for Windows, typically you don't have to worry about the underline generated application. One of the powerful features of React Native is that it generates a truly native application, which means that the JSX controls you place in the UI are translated with the equivalent native XAML control. This feature helps to deliver great performance and a familiar Fluent look & feel to your applications.

However, there are a few scenarios where you would need to access the underlying XAML infrastructure. Recently, I worked on an engagement with a customer who needed to show a flyout when specific actions occur. However, the flyout didn't have to be displayed in a fixed position, but near the control that generated the action (like the click of a button). Achieving this goal only using JSX isn't feasible for two reasons:

1. React Native is a technology to build cross-platform applications, while `Flyout` is a specific Windows control. As such, by default, React Native doesn't expose a JSX equivalent.
2. When you create a `Flyout`, you must link it to another XAML control (like a `Button`) by setting its `Flyout` property or by passing it as parameter to the `ShowAt()` method. We can't access this information in JSX.

In this blog post we'll learn how to support this scenario, by combining a native module and the `findNodeHandle()` React Native function.

 

### Create the native module

The first step is to create a native module, which we'll need to interact with the native XAML control. You can follow the guidance [on the official website](https://microsoft.github.io/react-native-windows/docs/native-modules-setup) to create a new one and add support for Windows. Once you have the basic infrastructure, we can add in the module class a method to display the flyout, as in the following example:

 

```
namespace ReactNativeInAppNotifications
{
    [ReactModule("inappnotifications")]
    internal sealed class ReactNativeModule
    {

        private ReactContext _reactContext;

        [ReactInitializer]
        public void Initialize(ReactContext reactContext)
        {
            _reactContext = reactContext;
        }

        [ReactMethod("showNotification")]
        public void ShowNotification(int tag, string title)
        {
            _reactContext.Handle.UIDispatcher.Post(() =>
            {
                Flyout flyout = new Flyout
                {
                    Content = new TextBlock { Text = title }
                };

                var control = XamlUIService.FromContext(_reactContext.Handle).ElementFromReactTag(tag) as FrameworkElement;

                flyout.ShowAt(control);
            });
        }
    }
}

```

First, notice how the class is decorated with the `[ReactModule]` attribute, while the `ShowNotification()` method is decorated with the `[ReactMethod]` attribute. They will enable us to access them from the JavaScript layer of the application. The `ShowNotification()` method accepts two parameters: one is the title of the notification, while the other one is a tag, which is an index that we can use to reference a JSX control. We'll learn later in the post, when we'll talk about the JavaScript layer, how to pass this information to the native module.

The next step is to create our `Flyout` control. In the previous snippet, we're using a very simple approach and we're setting the `Content` property with a new `TextBlock` control; then we set its `Text` property with the title that we're passing from the JavaScript layer. Since we are using native code, you have the flexibility to customize the `Flyout` control as you prefer: you can use a more complex XAML to define the `Content`; or you can customize other properties like `LightDismissOverlayMode` or `ShowMode`.

Now that we have our flyout, we need to display it near the control that triggered the action. As such, we need to use the tag we have received from the JavaScript layer to retrieve a reference to the corresponding XAML control. We can achieve this goal thanks to the `XamlUIService` class offered by React Native for Windows. First, we get an instance from the current context (which is exposed by the `Handle` property of the `ReactContext` object that is set in the `Initialize()` method of the module). Then, we call the `ElemenFromReactTag()` method, passing as parameter the tag we have received. In the end, we cast the result into a `FrameworkElement` object, which is the base class of XAML controls.

Now we have access to underline XAML control which triggered the event, so we can just pass it to `ShowAt()` method exposed by the `Flyout` control. This will make sure that the `Flyout` will be displayed near the control.

Let's see now the code that we have to write in the React Native layer to use the native module we have just written.

 

### Invoke the native module from JavaScript

Let's now create a React Native component that we can use to display the notification. Let's see the code first, then we'll comment it.

 

```
import React from 'react';
import {Button, NativeModules, findNodeHandle} from 'react-native';

class NotificationComponent extends React.Component {

    constructor(props) {
        super(props);
        this.myButton = React.createRef();
    }

  showNotification = async () => {
    await NativeModules.inappnotifications.showNotification(findNodeHandle(this.myButton.current), 'Hello World');
  };

  render() {
    return (
      <Button
        title="Click me"
        onPress={this.showNotification}
        ref={this.myButton} />
    );
  }
}

export default NotificationComponent;

```

In order to pass to the native module the JSX control which triggered the event, we need to use the concept of reference in React Native. You can think of it like the `x:Name` property in XAML: it's a way to directly reference a control from code. If this approach is frequently used in other platforms (like WPF or Windows Forms), it's not very common in React Native. In most of the scenarios, in fact, you won't need to directly access to the control, but you're going to use properties, events and state to implement the logic you need.

However, there are scenarios (like this one) in which a reference is the only way to achieve a goal and, as such, React Native provides the infrastructure to implement it. This is achieved with two changes to the code:

- In the constructor of the component, we define a variable (in this case, `myButton`) and we initialize it by calling `React.createRef()`.
- In JSX, we set the `ref` property of the control we want to reference (in this sample, a `Button` control) with the same variable we have created in the constructor (in this case, `myButton`).

Now we can access to the control by using the `current` property of the `myButton` object. We have everything we need now, so we can call the `showNotification()` method exposed by our native module, through the `NativeModules` object offered by React Native. Remember that the syntax to use a native module is `NativeModule.<class name>.<method name>`. In our example, it's `NativeModules.inappnotifications.showNotification`.

Well, we have almost everything we need, there's one last thing to add. Remember that the `ShowNotification()` method in the native module requires a tag to reference the XAML control? To translate our reference to a tag, we must use the `findNodeHandle()` method offered by React Native. This is how the implementation looks like:

```
showNotification = async () => {
await NativeModules.inappnotifications.showNotification(findNodeHandle(this.myButton.current), 'Hello World');
};

```

To get the tag, we invoke `findNodeHandle()` passing, as parameter, the `current` property of the `myButton` reference we have created earlier.

In the end, we just connect the `showNotification()` method we have just created to the `onPress` event of the `Button` control, so that we can invoke it when it's clicked.

 

 

### Wrapping up

That's it! Now, if you launch your React Native for Windows application and you press the button, you will see the flyout being displayed right at the top of the Button:

 

![Flyout.png](https://techcommunity.microsoft.com/t5/image/serverpage/image-id/373197i4C571ACAA7D52D7F/image-size/large?v=v2&px=999 "Flyout.png")

 

You can test the full code with the sample application [on GitHub](https://github.com/qmatteoq/InAppNotifications). Happy coding!