Skip to content
Adam Comella edited this page Dec 19, 2016 · 23 revisions

Intro

react-winjs is a library which exposes each WinJS control as a React component.

API Differences from WinJS

For the most part, the props of the react-winjs React components match the properties of the WinJS controls. Each React component has a few additional props which are applied to the root element of the WinJS control:

  • className: A string representing the element's CSS className.
  • style: An object where the keys are camel cased CSS attributes and the values are the corresponding values of those attributes. Similar to React's style prop, the values may be one of the following types:
    • string: Strings are left as is.
    • number: In general, the number is converted to a string and "px" is appended to it. Some CSS properties are unitless (e.g. opacity, flexGrow) and these numbers are left as is.
    • falsy: Falsy values except 0 are treated as an empty string so they end up clearing the CSS property.
  • id: A string representing the element's id.
  • aria-controls, aria-expanded: A string representing the value of the aria attribute.

What's interesting about a control's root element is that, not only might you want to manipulate it from React, but WinJS controls themselves typically manipulate their root elements. For example, the ListView will add classes such as win-listview and win-disposable to its root element. react-winjs implements the style and className props specially such that you can contribute to the root element's class names and styles without stomping on the ones that WinJS added.

Accessing the winControl

Each component provides a property called winControl which returns the instance of the WinJS control. For example, winControl on a react-winjs ListView component will return an instance of WinJS.UI.ListView.

Events

Events are exposed as camel cased props that begin with on. For example, WinJS's onbeforeshow event is exposed as the onBeforeShow prop.

Special Props

Some react-winjs components have additional props which don't map directly to any property on the WinJS control. For example, the react-winjs SplitView has a paneComponent prop which enables you to specify the pane's content as a React component. Such special props are noted under the documentation for the particular control.

Utility Functions

  • reactRenderer(componentFunction): Enables an itemTemplate to be specified as a React component. Given a function that returns a React component, returns an item renderer function that can be used with WinJS controls. See the FlipView and ListView examples.

Controls: Example Usages

AppBar

<ReactWinJS.AppBar>
    <ReactWinJS.AppBar.Button key="home" icon="home" label="Home" />
    <ReactWinJS.AppBar.Button key="save" icon="save" label="Save" />
</ReactWinJS.AppBar>

In WinJS, there is the WinJS.UI.AppBarCommand which has a type property. react-winjs differs in that it provides several components which map to WinJS.UI.AppBarCommand and each corresponds to a different value of the type property. Here's a summary of how that works:

react-winjs Component WinJS.UI.AppBarCommand type Property Notes
ReactWinJS.AppBar.Button "button"
ReactWinJS.AppBar.Toggle "toggle" Control its state with the selected prop
ReactWinJS.AppBar.Separator "separator"
ReactWinJS.AppBar.ContentCommand "content" Provide the custom content as the child
ReactWinJS.AppBar.FlyoutCommand "flyout" Provide the Flyout/Menu with the flyoutComponent prop

Limitations:

  • Each AppBar command must have a key.
  • The AppBar command's ref prop does not work.

Special props for AppBar.FlyoutCommand:

  • flyoutComponent: Takes a React component and uses it as the Flyout/Menu associated with the FlyoutCommand.

AutoSuggestBox

<ReactWinJS.AutoSuggestBox placeholderText="Type a city" />

BackButton

<ReactWinJS.BackButton />

ContentDialog

<ReactWinJS.ContentDialog
  ref="dialog"
  title="Urgent Message"
  primaryCommandText="OK"
  secondaryCommandText="Cancel"
>
  <div>
    This content will appear in the body of the ContentDialog. You can put <i>arbitrary</i> HTML in here.
  </div>
</ReactWinJS.ContentDialog>

// ...

// In an event handler:
this.refs.dialog.winControl.show().then(function (eventObject) {
  // eventObject.result tells you what caused the dialog to get dismissed.
});

DatePicker

<ReactWinJS.DatePicker current={this.state.date} onChange={this.handleDateChange} />

FlipView

<ReactWinJS.FlipView
  itemDataSource={this.props.ratingsList.dataSource}
  itemTemplate={this.flipViewItemRenderer}
  onPageSelected={this.handlePageSelected} />

// ...

// itemDataSource
ratingsList: new WinJS.Binding.List([{ rating: 4 }, { rating: 2 }])

// itemTemplate
flipViewItemRenderer: ReactWinJS.reactRenderer(function (item) {
  return <div>This flip view item's rating is: {item.data.rating}</div>;
})

Flyout

<ReactWinJS.Flyout ref="flyout">
  <div>This is the flyout content!!</div>
</ReactWinJS.Flyout>

// ...

// In an event handler:
this.refs.flyout.winControl.show(anchorElement);

Hub

<ReactWinJS.Hub>
    <ReactWinJS.Hub.Section key="sectionA" header="First section" isHeaderStatic={true}>
      <div>Hubs are useful for varied content</div>
    </ReactWinJS.Hub.Section>
    <ReactWinJS.Hub.Section key="sectionB" header="The second section">
      <div>This hub is boring however, it only contains one piece of dynamic content: {ratings.length}</div>
    </ReactWinJS.Hub.Section>
    <ReactWinJS.Hub.Section key="sectionC" header="The tail...">
      <div>Because it's only purpose is to show how to create a hub</div>
    </ReactWinJS.Hub.Section>
</ReactWinJS.Hub>

Limitations:

  • Each Hub.Section must have a key.
  • The Hub.Section's ref prop does not work.

ItemContainer

<ReactWinJS.ItemContainer>
  <div>
    An ItemContainer is a wrapper around content that adds
    pressed and selection behaviors!
  </div>
</ReactWinJS.ItemContainer>

ListView

<ReactWinJS.ListView
  itemDataSource={this.props.ratingsList.dataSource}
  itemTemplate={listViewItemRenderer}
  layout={listViewLayout} />

// ...

// itemDataSource
ratingsList: new WinJS.Binding.List([{ rating: 4 }, { rating: 2 }])

// itemTemplate
listViewItemRenderer: ReactWinJS.reactRenderer(function (item) {
  return <div>This list view item's rating is: {item.data.rating}</div>;
})

// layout
listViewLayout: { type: WinJS.UI.ListLayout }

Special props:

  • headerComponent: Takes a React component and uses it as the header of the ListView.
  • footerComponent: Takes a React component and uses it as the footer of the ListView.

Menu

<ReactWinJS.Menu ref="menu">
    <ReactWinJS.Menu.Button key="commandA" label="command the first" />
    <ReactWinJS.Menu.Button key="commandB" label="command the second" />
</ReactWinJS.Menu>

// ...

// In an event handler:
this.refs.menu.winControl.show(anchorElement);

In WinJS, there is the WinJS.UI.MenuCommand which has a type property. react-winjs differs in that it provides several components which map to WinJS.UI.MenuCommand and each corresponds to a different value of the type property. Here's a summary of how that works:

react-winjs Component WinJS.UI.MenuCommand type Property Notes
ReactWinJS.Menu.Button "button"
ReactWinJS.Menu.Toggle "toggle" Control its state with the selected prop
ReactWinJS.Menu.Separator "separator"
ReactWinJS.Menu.FlyoutCommand "flyout" Provide the Flyout/Menu with the flyoutComponent prop

Limitations:

  • Each Menu command must have a key.
  • The Menu command's ref prop does not work.

Special props for Menu.FlyoutCommand:

  • flyoutComponent: Takes a React component and uses it as the Flyout/Menu associated with the FlyoutCommand.

Pivot

<ReactWinJS.Pivot>
    <ReactWinJS.Pivot.Item key="itemA" header="First">
      <div>Pivots are useful for varied content</div>
    </ReactWinJS.Pivot.Item>
    <ReactWinJS.Pivot.Item key="itemB" header="Second">
      <div>This Pivot is boring however, it only contains one piece of dynamic content: {ratings.length}</div>
    </ReactWinJS.Pivot.Item>
    <ReactWinJS.Pivot.Item key="itemC" header="Tail...">
      <div>Because it's only purpose is to show how to create a Pivot</div>
    </ReactWinJS.Pivot.Item>
</ReactWinJS.Pivot>

Limitations:

  • Each Pivot.Item must have a key.
  • The Pivot.Item's ref prop does not work.

Special props:

  • customLeftHeaderComponent: Takes a React component and uses it as the customLeftHeader of the Pivot.
  • customRightHeaderComponent: Takes a React component and uses it as the customRightHeader of the Pivot.

Rating

<ReactWinJS.Rating maxRating={5} userRating={this.state.rating} />

SemanticZoom

var zoomedInView = <ReactWinJS.ListView
  itemDataSource={ratingsList.dataSource}
  itemTemplate={zoomedInItemRenderer}
  groupDataSource={ratingsList.groups.dataSource}
  groupHeaderTemplate={zoomedInHeaderRenderer}
  layout={zoomedInLayout} />;

var zoomedOutView = <ReactWinJS.ListView
  itemDataSource={ratingsList.groups.dataSource}
  itemTemplate={zoomeOutItemRenderer}
  layout={zoomedOutLayout} />;

<ReactWinJS.SemanticZoom
  zoomedInComponent={zoomedInView}
  zoomedOutComponent={zoomedOutView} />

// ...

// itemDataSource
function groupKey(item) {
    return item.group;
}
function groupData(item) {
    return { title: item.group; };
}
ratingsList: new WinJS.Binding.List([
  { rating: 4, group: "A" },
  { rating: 2, group: "A" },
  { rating: 8, group: "B" },
  { rating: 3, group: "B" }
]).createGrouped(groupKey, groupData);

// renderers
zoomedInItemRenderer: ReactWinJS.reactRenderer(function (item) {
  return <div>This list view item's rating is: {item.data.rating}</div>;
})
zoomedInHeaderRenderer: ReactWinJS.reactRenderer(function (item) {
  return <div>{item.data.title}</div>;
})
zoomeOutItemRenderer: ReactWinJS.reactRenderer(function (item) {
  return <div>{item.data.title}</div>;
})

// layouts
zoomedInLayout: { type: WinJS.UI.ListLayout }
zoomedOutLayout: { type: WinJS.UI.ListLayout }

Special props:

  • zoomedInComponent: Takes a React component and uses it as the zoomed in view of the SemanticZoom.
  • zoomedOutComponent: Takes a React component and uses it as the zoomed out view of the SemanticZoom.

SplitView and SplitViewPaneToggle

var splitViewId = "mySplitView";
var pane = (
  <div>
    <ReactWinJS.SplitViewPaneToggle
      aria-controls={splitViewId}
      paneOpened={this.state.paneOpened} />

    <ReactWinJS.SplitView.Command
      label="Home"
      icon="home"
      onInvoked={this.handleGoToHome} />
    <ReactWinJS.SplitView.Command
      label="Settings"
      icon="settings"
      onInvoked={this.handleGoToSettings} />
  </div>
);

<ReactWinJS.SplitView
  id={splitViewId}
  paneComponent={pane}
  contentComponent={<div>SplitView Content Area</div>}
  paneOpened={this.state.paneOpened}
  onAfterClose={this.handlePaneClosed} />

Special props for SplitView:

  • paneComponent: Takes a React component and mounts it inside of the paneElement of the SplitView.
  • contentComponent: Takes a React component and mounts it inside of the contentElement of the SplitView.

Special props for SplitViewPaneToggle:

  • paneOpened: A boolean representing whether or not the SplitView pane associated with the SplitViewPaneToggle is opened. This information is communicated to screen reader users when they put focus on the SplitViewPaneToggle. In order for this to work, it's also important that the SplitView's id prop matches the SplitViewPaneToggle's aria-controls prop.

TimePicker

<ReactWinJS.TimePicker current={this.state.time} />

ToggleSwitch

<ReactWinJS.ToggleSwitch
  checked={this.props.toggleOn}
  onChange={this.handleToggle}
  labelOn="Switch is On"
  labeOff="Switch is Off" />

ToolBar

<ReactWinJS.ToolBar>
    <ReactWinJS.ToolBar.Button key="add" label="This is a ToolBar command" icon="add" />
    <ReactWinJS.ToolBar.Button key="remove" label="Another ToolBar command" icon="remove" />
</ReactWinJS.ToolBar>

In WinJS, there is the WinJS.UI.Command which has a type property. react-winjs differs in that it provides several components which map to WinJS.UI.Command and each corresponds to a different value of the type property. Here's a summary of how that works:

react-winjs Component WinJS.UI.Command type Property Notes
ReactWinJS.ToolBar.Button "button"
ReactWinJS.ToolBar.Toggle "toggle" Control its state with the selected prop
ReactWinJS.ToolBar.Separator "separator"
ReactWinJS.ToolBar.ContentCommand "content" Provide the custom content as the child
ReactWinJS.ToolBar.FlyoutCommand "flyout" Provide the Flyout/Menu with the flyoutComponent prop

Limitations:

  • Each ToolBar command must have a key.
  • The ToolBar command's ref prop does not work.

Special props for ToolBar.FlyoutCommand:

  • flyoutComponent: Takes a React component and uses it as the Flyout/Menu associated with the FlyoutCommand.

Tooltip

<ReactWinJS.Tooltip
  contentComponent={<div>This can have arbitrary content, like images...</div>}>
  <div>This has a tooltip, hover and see...</div>
</ReactWinJS.Tooltip>

Special props:

  • contentComponent: Takes a React component and uses it as the contentElement of the Tooltip.