Skip to main content

Creating Your First Component

Building an Instrument Template

In MSFS, all HTML instruments require a HTML template to render to, as well as to pull in any other Javascript and CSS that go along with the instrument. Create a file MyInstrument.html in your project root with the following content:

<script type="text/html" id="MyInstrument">
<div id="InstrumentContent"></div>
</script>

<link rel="stylesheet" href="MyInstrument.css" />
<script type="text/html" import-script="/Pages/VCockpit/Instruments/MyInstrument/MyInstrument.js"></script>

This is a very basic template that can be loaded by the MSFS VCockpit system. First we defined a HTML template, where we put just one div element with the ID InstrumentContent. We then name this HTML template with the ID MyInstrument. This ID will be used later to inform the VCockpit system which HTML template to use to display the instrument.

We then link to our bundled CSS stylesheet, which we will place alongside our HTML. Finally, we link what will become our bundled and compiled Javascript using the VCockpit import-script attribute. This lets the VCockpit system bootstrap its own dependencies, and then load any further dependencies it finds with import-script attributes.

Linking Your Instrument to Code

In the MSFS VCockpit system, all instruments must originate and extend from the class BaseInstrument. This class contains code that the system communicates with to bootstrap and initialize the instrument, and place it into the HTML that is displayed on the screen in the simulator. It is then possible to register that class with the VCockpit system as the instrument to be displayed.

Create a file MyInstrument.tsx in the project root alongside your MyInstrument.html file. Add the following code to the file:

/// <reference types="@microsoft/msfs-types/Pages/VCockpit/Core/VCockpit" />

class MyInstrument extends BaseInstrument {
get templateID(): string {
return 'MyInstrument';
}
}

registerInstrument('my-instrument', MyInstrument);

Note that this class contains the property templateID, which returns a string. This property must be provided and the returned string must match the name of your instrument template you provided in the HTML, in this case MyInstrument.

Finally, we call the VCockpit function registerInstrument() to register our instrument class with the system. This function takes two parameters: the name that you would like to give your instrument (any name is fine, and need not match any other IDs or tags), and the instrument class for the VCockpit system to instantiate.

note

registerInstrument is a method that comes from the underlying MSFS JS SDK, and is not part of the avionics framework. As such it needs to be referenced from the msfs-types module, which is what the first line of the sample code does. You will need to include a similar reference for any other methods that come from the underlying SDK.

Building a Hello World Component

We are going to create a very simple component that displays the text Hello World! on the page, within the instrument. Create a file MyComponent.tsx in the project root, and add the following code:

import { FSComponent, DisplayComponent, VNode } from '@microsoft/msfs-sdk';

export class MyComponent extends DisplayComponent<any> {
public render(): VNode {
return (
<div class='my-component'>Hello World!</div>
);
}
}

Let's go through what's happening in this code a bit.

Framework Imports

import { FSComponent, DisplayComponent, VNode } from '@microsoft/msfs-sdk';

In order to use code from the framework, it must be imported into the TypeScript file. While a complete discussion of the usage of imports is beyond the scope of these documents, do note that in order to use JSX within a component, you must at least import FSComponent. This is similar to needing to import react when using React components.

DisplayComponent

export class MyComponent extends DisplayComponent<any> {
...

In the FSComponent framework, all components must extend from DisplayComponent, much like in React, all class components must extend from React.Component. All components must implement at least one public method, named render(), that returns some JSX elements. When the component is rendered to the DOM, this is what will be placed there. This can contain other HTML elements, like divs, other components, or any combination of the two.

In this way, just as in React, one can compose components and HTML together seamlessly.

Rendering Your Component

Right now, our component lives on its own, ready to display its contents, but it has not been rendered anywhere into our instrument. Go back to the MyInstrument.tsx file and add the following to the top of the file to import our component as well as enable the usage of JSX:

import { FSComponent } from '@microsoft/msfs-sdk';
import { MyComponent } from './MyComponent';

Then, add this implementation of connectedCallback() to the MyInstrument class:

public connectedCallback(): void {
super.connectedCallback();

FSComponent.render(<MyComponent />, document.getElementById('InstrumentContent'));
}
caution

Always call super.connectedCallback() first thing in any implementation of BaseInstrument.connectedCallback(). The base class does important work that is necessary for your instrument to function inside its implementation. Failing to call super will cause your instrument to fail during load.

The full contents of your file should now look like:

/// <reference types="@microsoft/msfs-types/Pages/VCockpit/Core/VCockpit" />

import { FSComponent } from '@microsoft/msfs-sdk';
import { MyComponent } from './MyComponent';

class MyInstrument extends BaseInstrument {
get templateID(): string {
return 'MyInstrument';
}

public connectedCallback(): void {
super.connectedCallback();

FSComponent.render(<MyComponent />, document.getElementById('InstrumentContent'));
}
}

registerInstrument('my-instrument', MyInstrument);

FSComponent.render()

You may notice that we added a call to FSComponent.render() in our instrument's connectedCallback() function. Like React.render(), this function takes JSX and renders it to the specified element. In this case, we are taking our newly created MyComponent component, and rendering it to the element with the ID InstrumentContent. This was the ID that we gave our single div element inside our instrument template.

The method connectedCallback() will be called by the browser DOM when the MyInstrument element, registered via registerInstrument(), is instantiated fully and inserted into the DOM on the page. Therefore, our component will be rendered using FSComponent.render() once the instrument is in the DOM, and guarantees that the div with the ID InstrumentContent is available to render to.

Build Your Component

You can now build your component using the NPM script that we added in the previous steps:

> npm run build

This will run our Rollup build and output our built files to the build folder. You can then copy the HTML file from the root and the compiled Javascript file from build to your MSFS package sources folder, and run your package build and resync in MSFS to see your instrument on your panel.

info

The location of the Javascript file within the package sources must match the path that was provided in the HTML template import-script attribute. In this case, that attribute is set to /Pages/VCockpit/Instruments/MyInstrument/MyInstrument.js. All HTML sources loaded by the Coherent GT framework in MSFS reside in the html_ui root folder, so the final package folder path that you should copy the file to should be html_ui/Pages/VCockpit/Instruments/MyInstrument/MyInstrument.js.