2021-03-30 09:37:33 +03:00
# Using react-native-xaml
## Requirements
2021-07-25 21:30:39 +03:00
react-native-xaml works best on the latest supported react-native-windows version.
2021-03-30 09:37:33 +03:00
To include react-native-xaml in your app, just add it to your package.json:
`yarn add react-native-xaml --save`
Then autolinking will take care of the rest!
2021-07-25 21:30:39 +03:00
The stock react-native-xaml package includes projections for all XAML types (i.e. "system XAML") as well as WinUI 2.6.
## :exclamation: **Important**
You must update your app to use WinUI 2.6 or later. See the instructions at https://microsoft.github.io/react-native-windows/docs/customizing-sdk-versions.
2021-03-30 09:37:33 +03:00
2021-07-23 20:30:07 +03:00
If you want to use an existing `UserControl` (e.g. from a library you've already written), you will want to generate a custom projection for your project.
2021-03-30 09:37:33 +03:00
For more information on generating a custom projection, please see the [Technical Guide ](TechnicalGuide.md ).
2021-07-23 10:42:54 +03:00
# Sample usage - UWP XAML
2021-03-30 09:37:33 +03:00
Below are usage examples of some controls and features of react-native-xaml.
If you have questions about a scenario you don't see below, please [file an issue ](https://github.com/asklar/react-native-xaml/issues/new )!
2021-03-24 23:55:49 +03:00
## Basic example (children, events, properties)
2021-03-30 09:37:33 +03:00
2021-03-24 23:55:49 +03:00
```jsx
< StackPanel orientation = "horizontal" >
2021-07-05 00:55:42 +03:00
< HyperlinkButton content = "Click me!" onClick = {(args) = > {
2021-03-25 10:55:56 +03:00
alert(`clicked! Native event args: ${JSON.stringify(args.nativeEvent)}`);
}} />
< Border verticalAlignment = "center" background = "paleturquoise" >
< TextBlock text = "this is a textblock" foreground = 'red' textAlignment = "center" / >
< / Border >
< TextBlock text = "this is another textblock" foreground = 'green' textAlignment = "center" / >
2021-07-05 00:55:42 +03:00
< Button content = "this is a button" onClick = {() = > { alert("you clicked the button!"); }} />
2021-03-24 23:55:49 +03:00
< / StackPanel >
```
## Text
2021-03-30 09:37:33 +03:00
2021-03-24 23:55:49 +03:00
```jsx
2021-09-24 04:06:42 +03:00
< TextBlock foreground = "black" xamlPadding = {20} xamlMargin = {20} >
2021-03-24 23:55:49 +03:00
< Run text = "hello world!" / >
< LineBreak / >
< Italic >
2021-03-25 10:55:56 +03:00
< Run text = "hi there" / >
2021-03-24 23:55:49 +03:00
< / Italic >
< Hyperlink navigateUri = "http://bing.com" >
< Run text = "Go to bing" / >
< / Hyperlink >
< / TextBlock >
```
## Menu
2021-03-30 09:37:33 +03:00
2021-03-24 23:55:49 +03:00
```jsx
2021-03-25 10:55:56 +03:00
[isOpen, setIsOpen] = useState(false);
2021-03-24 23:55:49 +03:00
< TextBox text = "this is a textbox with a menuFlyout" foreground = "red" >
2021-03-25 10:55:56 +03:00
< MenuFlyout isOpen = {isOpen} onClosed = {() = > {
setIsOpen(false);
2021-03-24 23:55:49 +03:00
}} >
2021-03-25 10:55:56 +03:00
< MenuFlyoutItem text = "option 1" onClick = {(x) = > { alert(JSON.stringify(x.nativeEvent)); setOption("option 1"); }} />
< MenuFlyoutItem text = "option 2" onClick = {() = > { alert("clicked 2"); setOption("option 2"); }}/>
2021-03-24 23:55:49 +03:00
< / MenuFlyout >
< / TextBox >
2021-07-05 00:55:42 +03:00
< Button content = {`Last selected option = ${option} $ { count } ` }
2021-03-25 10:55:56 +03:00
onClick={(a) => {
setIsOpen(true); }} />
2021-03-24 23:55:49 +03:00
```
2022-06-21 21:26:36 +03:00
Menus can contain cascading items:
```jsx
< MenuFlyout . . . >
< MenuFlyoutSubItem text = 'subitem 1' >
< MenuFlyoutItem text = 'item 1' / >
< MenuFlyoutItem text = 'item 2' / >
< MenuFlyoutItem text = 'item 3' / >
< / MenuFlyoutSubItem >
< MenuFlyoutSubItem text = 'subitem 2' >
< MenuFlyoutItem text = 'item 4' / >
< MenuFlyoutItem text = 'item 5' / >
< MenuFlyoutItem text = 'item 6' / >
< / MenuFlyoutSubItem >
< / MenuFlyout >
```
2022-02-10 20:45:40 +03:00
## MenuBar
```jsx
< MenuBar >
< MenuBarItem title = "File" >
< MenuFlyoutItem text = "Help" / >
< MenuFlyoutItem text = "Settings" / >
< / MenuBarItem >
< MenuBarItem title = "View" / >
< / MenuBar >
```
2021-07-06 08:07:06 +03:00
## Image
- For Image, note that you should specify its size so that RN reserves space for it, otherwise the image won't show.
2021-10-22 04:50:40 +03:00
- Supports Bitmap images and SVG files URIs, as well as inline Base64-encoded data:
2021-07-06 08:07:06 +03:00
```jsx
< Image source = "https://microsoft.github.io/react-native-windows/img/homepage/cross-platform.png"
width={200} height={100} />
```
2021-10-22 04:50:40 +03:00
```jsx
< Image
source="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4gPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyOCAyOCIgZmlsbD0ibm9uZSI+PHBhdGggZD0iTTEzLjEyNSAwSDBWMTMuMTI1SDEzLjEyNVYwWiIgZmlsbD0iI0YyNTAyMiI+PC9wYXRoPjxwYXRoIGQ9Ik0yOCAwSDE0Ljg3NVYxMy4xMjVIMjhWMFoiIGZpbGw9IiM3RkJBMDAiPjwvcGF0aD48cGF0aCBkPSJNMTMuMTI1IDE0Ljg3NUgwVjI4SDEzLjEyNVYxNC44NzVaIiBmaWxsPSIjMDBBNEVGIj48L3BhdGg+PHBhdGggZD0iTTI4IDE0Ljg3NUgxNC44NzVWMjhIMjhWMTQuODc1WiIgZmlsbD0iI0ZGQjkwMCI+PC9wYXRoPjwvc3ZnPiA="
width={80}
height={80} />
```
2021-03-24 23:55:49 +03:00
## ComboBox
2021-03-30 09:37:33 +03:00
2021-03-24 23:55:49 +03:00
```jsx
2021-07-05 00:55:42 +03:00
< ComboBox text = "this is a combobox" description = "best bois"
2021-03-25 10:55:56 +03:00
onSelectionChanged={(args) =>
{ alert(`sel changed! Native event args: ${JSON.stringify(args.nativeEvent)}`); }
} >
2021-07-05 00:55:42 +03:00
< ComboBoxItem content = "garfield" foreground = "black" / >
< ComboBoxItem content = "snoopy" foreground = "black" / >
2021-03-25 10:55:56 +03:00
< / ComboBox >
2021-03-24 23:55:49 +03:00
```
2021-05-01 05:24:34 +03:00
## AutoSuggestBox
```jsx
< AutoSuggestBox placeholderText = "placeholder text" >
< SymbolIcon symbol = {Symbol.Find}/ >
< / AutoSuggestBox >
```
2021-06-15 20:41:49 +03:00
## Grid
```jsx
2021-06-15 20:50:50 +03:00
< Grid gridLayout = {{columns: [ 60 , 60 , ' * ' ] , rows: [ 100 , 100 , 100 ] } } >
2021-06-15 20:41:49 +03:00
< TextBlock text = "hello" gridRow = {2} gridColumn = {2} / >
< TextBlock text = "world" gridRow = {1} gridColumn = {1} / >
< TextBlock gridRow = {2} gridColumn = {1} text = 'hi there' / >
< / Grid >
```
Note that only react-native-xaml components will respect the `gridRow` /`gridColumn` properties inside a `Grid` , core controls will not do that.
2021-03-25 05:09:33 +03:00
## NavigationView
2021-03-30 09:37:33 +03:00
2021-03-25 05:09:33 +03:00
```jsx
2021-12-28 20:23:19 +03:00
const [text, setText] = React.useState('initial text');
< WinUI.NavigationView width = {700} height = {700} >
< WinUI.NavigationViewItem content = 'Item 1' onTapped = {() = > setText('text #1 ')} priority={NavigationViewPriority.MenuItem}>
2021-03-30 20:21:42 +03:00
< FontIcon glyph = "" / >
2021-12-28 20:23:19 +03:00
< / WinUI.NavigationViewItem >
< WinUI.NavigationViewItem content = 'Item 2' onTapped = {() = > setText('text #2 ')} priority={NavigationViewPriority.FooterMenuItem}/>
< TextBlock text = {text} priority = {NavigationViewPriority.Content}/ >
< / WinUI.NavigationView >
2021-03-25 05:09:33 +03:00
```
2021-07-04 14:06:00 +03:00
## CommandBar with AppBarButtons and KeyboardAccelerators
2021-07-04 10:01:50 +03:00
```jsx
< CommandBar isOpen = {true} style = {{ height: 56 } } >
< AppBarButton
2021-08-02 23:19:11 +03:00
priority={CommandBarPriority.PrimaryCommand}
2021-07-04 10:01:50 +03:00
label="Search"
onClick={() => { alert('search'); }}>
< SymbolIcon symbol = {Symbol.Find} / >
2021-07-04 14:06:00 +03:00
< KeyboardAccelerator
virtualKey={VirtualKey.S}
modifiers={VirtualKeyModifiers.Menu} />
2021-07-04 10:01:50 +03:00
< / AppBarButton >
< AppBarButton
2021-08-02 23:19:11 +03:00
priority={CommandBarPriority.PrimaryCommand}
2021-07-04 10:01:50 +03:00
label="Calendar">
< SymbolIcon symbol = {Symbol.Calendar} / >
< / AppBarButton >
2021-08-02 23:19:11 +03:00
< AppBarButton label = "Audio" priority = {CommandBarPriority.SecondaryCommand} >
2021-07-04 10:01:50 +03:00
< SymbolIcon symbol = {Symbol.Audio} / >
< / AppBarButton >
< AppBarButton
label="Calculator"
2021-08-02 23:19:11 +03:00
priority={CommandBarPriority.SecondaryCommand}>
2021-07-04 10:01:50 +03:00
< SymbolIcon symbol = {Symbol.Calculator} / >
< / AppBarButton >
< / CommandBar >
```
2021-07-11 04:09:50 +03:00
## ContentDialog
```jsx
const [showState, setShowState] = useState(ContentDialogState.Hidden);
< Button
onTapped={a => {setShowState(ContentDialogState.Popup);}}
content="click to open a ContentDialog" />
< ContentDialog
showState={showState}
defaultButton={ContentDialogButton.Close}
title="the title"
content="this is the content"
closeButtonText="close"
primaryButtonText="primary"
secondaryButtonText="secondary"
onPrimaryButtonClick={e => {
alert('primary');
}}
onSecondaryButtonClick={e => {
alert('secondary');
}}
onContentDialogClosed={e => {
setShowState(ContentDialogState.Hidden);
alert(e.nativeEvent);
}} />
```
2021-07-04 14:06:00 +03:00
2021-07-24 00:23:26 +03:00
## SplitView
```jsx
const [isOpen, setIsOpen] = useState(false);
// ...
< SplitView
isPaneOpen={isOpen}
onPaneClosed={() => {
setIsOpen(false);
}}
width={800}
height={300}
paneBackground="red"
panePlacement={SplitViewPanePlacement.Left}>
< TextBlock
text="this is in the pane"
priority={SplitViewPriority.Pane}
foreground="white"
/>
< Grid
background="green"
priority={SplitViewPriority.Content}
gridLayout={{rows: [200], columns: [200]}}>
< TextBlock text = "this is in the content" foreground = "white" / >
< / Grid >
< / SplitView >
< Button
foreground="#992222"
onTapped={a => {
setIsOpen(!isOpen);
}}
content="button"
/>
```
2021-07-11 06:16:05 +03:00
## Path & vector graphics
```jsx
< Path
data="M14,2H12V1H11V2H5V1H4V2H2V14H14ZM4,3V4H5V3h6V4h1V3h1V5H3V3Zm9,10H3V6H13ZM7,10V7H4v3ZM5,8H6V9H5Z"
width={16}
height={16}
fill="red"
horizontalAlignment={HorizontalAlignment.Center}
verticalAlignment={VerticalAlignment.Center}
/>
```
2021-03-24 23:55:49 +03:00
## Lightweight styling
2021-03-30 09:37:33 +03:00
2021-03-24 23:55:49 +03:00
```jsx
< Button content = "Hello with style!" resources = {{
2021-03-25 10:55:56 +03:00
ButtonForeground: "#00fff1",
ButtonForegroundPressed: "#2090ff",
}} />
2021-03-24 23:55:49 +03:00
```
2021-03-30 09:37:33 +03:00
## Event args
react-native-xaml supports raising events and sending event args to the registered JavaScript event handlers. The native XAML event args object is projected to JavaScript through the `nativeEvent` method:
```jsx
2021-07-05 00:55:42 +03:00
< HyperlinkButton content = "Click me!"
2021-03-30 09:37:33 +03:00
onClick={(args) => {
alert(JSON.stringify(args.nativeEvent));
}} />
```
The content of the native event args object depends on whether the app is using Direct debugging or Web debugging.
- In web debugging mode, only certain properties on the sender and args are exposed. There is some special casing for a small number of events so that the "important properties" for the event can be projected to JavaScript. These properties must be of simple types (`number`, `string` , `boolean` , arrays of simple types, or objects with members of simple types).
- In direct debugging mode, react-native-xaml uses _codegen_ to infer how to marshal WinRT objects onto JavaScript by using JSI. This is a much richer and generic functionality. With this approach, you have access to the full set of properties on the event args and sender.
< details >
< summary > Sample JSON from an event args for a button being tapped< / summary >
```json
{
"sender": {
"flowDirection": 0,
"className": "Windows.UI.Xaml.Controls.Button",
"allowFocusOnInteraction": true,
"isFocusEngagementEnabled": false,
"focusVisualMargin": {
"left": -3,
"top": -3,
"right": -3,
"bottom": -3
},
"allowFocusWhenDisabled": false,
"background": "Black",
"isTextScaleFactorEnabled": true,
"focusVisualSecondaryBrush": "White",
"backgroundSizing": 1,
"borderBrush": "White",
"horizontalAlignment": 0,
"borderThickness": {
"left": 1,
"top": 1,
"right": 1,
"bottom": 1
},
"characterSpacing": 0,
"clickMode": 0,
"defaultStyleKey": {
"kind": 1,
"name": "Windows.UI.Xaml.Controls.Button"
},
"commandParameter": null,
"content": "button",
"focusVisualPrimaryThickness": {
"left": 2,
"top": 2,
"right": 2,
"bottom": 2
},
"dataContext": null,
"height": 32,
"defaultStyleResourceUri": null,
"elementSoundMode": 0,
"tabIndex": 2147483647,
"focusVisualPrimaryBrush": "Black",
"focusVisualSecondaryThickness": {
"left": 1,
"top": 1,
"right": 1,
"bottom": 1
},
"fontSize": 14,
"margin": {
"left": 0,
"top": 0,
"right": 0,
"bottom": 0
},
"fontStretch": 5,
"isTabStop": true,
"fontStyle": 0,
"foreground": "Dark red",
"horizontalContentAlignment": 1,
"tabNavigation": 0,
"isEnabled": true,
"isFocusEngaged": false,
"language": "en-US",
"maxHeight": null,
"maxWidth": null,
"tag": 13,
"minHeight": 0,
"minWidth": 0,
"name": "< reacttag > : 13",
"padding": {
"left": 8,
"top": 5,
"right": 8,
"bottom": 6
},
"requestedTheme": 0,
"requiresPointer": 0,
"verticalAlignment": 1,
"useSystemFocusVisuals": true,
"verticalContentAlignment": 1,
"width": 1200
},
"args": {
"className": "Windows.UI.Xaml.Input.TappedRoutedEventArgs",
"handled": false,
"pointerDeviceType": 2,
"originalSource": {
"flowDirection": 0,
"className": "Windows.UI.Xaml.Controls.TextBlock",
"allowFocusOnInteraction": true,
"focusVisualMargin": {
"left": 0,
"top": 0,
"right": 0,
"bottom": 0
},
"allowFocusWhenDisabled": false,
"characterSpacing": 0,
"maxLines": 0,
"isTextSelectionEnabled": false,
"focusVisualPrimaryThickness": {
"left": 2,
"top": 2,
"right": 2,
"bottom": 2
},
"dataContext": "button",
"focusVisualPrimaryBrush": "Black",
"isTextScaleFactorEnabled": true,
"focusVisualSecondaryBrush": "White",
"focusVisualSecondaryThickness": {
"left": 1,
"top": 1,
"right": 1,
"bottom": 1
},
"fontSize": 14,
"margin": {
"left": 0,
"top": 0,
"right": 0,
"bottom": 0
},
"fontStretch": 5,
"lineHeight": 0,
"fontStyle": 0,
"foreground": "Black",
"height": null,
"horizontalAlignment": 0,
"horizontalTextAlignment": 1,
"isColorFontEnabled": true,
"language": "en-US",
"lineStackingStrategy": 0,
"maxHeight": null,
"maxWidth": null,
"tag": null,
"minHeight": 0,
"minWidth": 0,
"name": "",
"opticalMarginAlignment": 0,
"padding": {
"left": 0,
"top": 0,
"right": 0,
"bottom": 0
},
"requestedTheme": 0,
"selectionHighlightColor": "Blue",
"text": "button",
"textAlignment": 1,
"textReadingOrder": 1,
"textLineBounds": 0,
"textDecorations": 0,
"textTrimming": 0,
"textWrapping": 1,
"verticalAlignment": 0,
"width": null
}
}
}
```
< / details >
In order to enable Direct debugging for your app, make sure that your App.cpp/App.cs has disabled web debugging:
< summary > C++< / summary >
2021-04-02 03:53:30 +03:00
2021-03-30 09:37:33 +03:00
```cpp
InstanceSettings().UseWebDebugger(false);
```
< summary > C#< / summary >
2021-04-02 03:53:30 +03:00
2021-03-30 09:37:33 +03:00
```cs
InstanceSettings.UseWebDebugger = false;
```
2021-07-23 10:42:54 +03:00
2022-01-26 20:03:22 +03:00
# Calling methods on XAML Event Args
By default, only XAML properties of event arg objects are exposed back. Some event args support calling methods on them.
See `eventArgMethods` in Windows.UI.Xaml.json.
Example:
```jsx
/// assume there is a MenuFlyout _menuRef defined.
< TextBlock
text="Hello"
onContextRequested={e => {
const tag = findNodeHandle(_tbRef.current);
const { point, returnValue } = e.nativeEvent.args.TryGetPosition(tag);
MenuFlyout.ShowAt(_menuRef, {point: point});
}}
/>
```
2021-09-25 04:17:36 +03:00
# Calling methods on XAML objects ("commands")
2021-11-15 21:29:42 +03:00
Some types support custom commands to expose some functionality of the underlying platform.
2022-01-26 20:03:22 +03:00
For example, this allows calling the programatically showing a flyout menu:
2021-09-25 04:17:36 +03:00
```jsx
const _tbRef = React.useRef< TextBlock > (null);
2021-11-15 21:29:42 +03:00
const _menuRef = useRef< MenuFlyout > (null);
2021-09-25 04:17:36 +03:00
2021-11-15 21:29:42 +03:00
const [x, setX] = React.useState(100);
2021-09-25 04:17:36 +03:00
// ...
return
2021-11-15 21:29:42 +03:00
< TextBox
text={x}
onBeforeTextChanging={e => {
setX(e.nativeEvent.args.newText);
}}
/>
< TextBlock
text="Hello"
onTapped={e => {
MenuFlyout.ShowAt(_menuRef, {point: {x: x, y: 42}});
}}
ref={t => {
_tbRef.current = t;
}}>
< MenuFlyout
ref={m => {
_menuRef.current = m;
}}>
< MenuFlyoutItem text = "menu option" / >
< / MenuFlyout >
< / TextBlock >
2021-09-25 04:17:36 +03:00
```
2021-07-23 10:42:54 +03:00
# Sample usage - WinUI controls
2021-07-23 20:30:07 +03:00
WinUI controls are available in the `WinUI` namespace.
2021-07-23 10:42:54 +03:00
## InfoBar
2021-08-06 02:10:53 +03:00
```jsx
2021-07-23 10:42:54 +03:00
const [visible, setVisible] = useState(Visibility.Visible);
2021-07-23 20:30:07 +03:00
// ...
< WinUI.InfoBar
2021-07-23 10:42:54 +03:00
message="the message"
title="the title"
isOpen={true}
visibility={visible}
onClosed={() => {
setVisible(Visibility.Collapsed);
}}
2021-07-23 20:30:07 +03:00
severity={WinUIEnums.InfoBarSeverity.Success}
/>
2021-08-06 02:10:53 +03:00
```