-
Notifications
You must be signed in to change notification settings - Fork 139
LEGACY UI Introduction
Vortex uses the react library (https://reactjs.org/) for its user interface, you will have to learn a bit about it to do anything useful with Vortex Extensions. Fortunately it’s not too complicated and there is plenty of tutorials and documentation on the Internet, so the following will focus on how it plays together with Vortex.
const APIView = require('./APIView').default;
function init(context) {
context.registerMainPage('filter', 'API', APIView, {
group: 'support',
props: () => ({ api: context.api }),
});
return true;
}
exports.default = init;
Not much is new here. We use registerMainPage to add a whole page, which will show up as a tab on the main navbar. filter is the name of a predefined icon we use, API the label. APIView is a custom react component that will be doing the rendering (see below).
group: ‘support’ specifies where on the navbar (if at all) the button will show up. The navbar is split into groups, from top to bottom they are ‘dashboard’, ‘global’, ‘per-game’ and ‘support’.
props specifies parameters that get passed to the react component, in this case we pass in the api so the component can do something with it. (This isn’t actually necessary as you will see later but this example is pretty contrived anyway).
const React = require('react');
const { ListGroup, ListGroupItem, Panel } = require('react-bootstrap');
const { MainPage } = require('vortex-api');
class APIView extends React.Component {
render() {
const { api } = this.props;
return React.createElement(MainPage, null,
React.createElement(MainPage.Body, null,
React.createElement(Panel, null,
React.createElement(Panel.Body, null,
React.createElement(ListGroup, null,
Object.keys(api).map((name, idx) =>
React.createElement(ListGroupItem, { key: idx }, name)
))))));
}
}
exports.default = APIView;
Now this looks a lot more “interesting”. First of all, we import a couple of modules, react is essentially what we use to create an html page from javascript, react-bootstrap is a helper library to use the famous bootstrap css framework from react and then vortex-api.
At this point you may be wondering
- “what modules can I import anyway?”: Good question. You can import any module that Vortex uses as well without problem. There will be a list in the reference. You can use any other modules as well but then it would be best you used webpack to create a single-file bundle for distribution (See later example).
- “what is this vortex-api and how is it different from the api object we got in context?”: These are really two separate things, I’m just not too creative with names. The context.api object is a stateful object that you use to communicate with vortex (like a handle) whereas vortex-api is more of a library of convenience functionality. There shouldn’t be anything in vortex-api you absolutely need to write an extension, it just makes it easier.
Ok, past the imports we declare a class which is our react component with a single function render. This function will be called automatically by react as necessary to generate html to be displayed. What this render function does is create a html subtree that gets inserted into the DOM. The example generates html like this (slightly simplified):
<div class="main-page">
<div class="main-page-body">
<div class="panel">
<div class="panel-body">
<ul class="list-group">
<li class="list-group-item">showErrorNotification</li>
...
</ul>
</div>
</div>
</div>
</div>
So React.createElement(MainPage, … generates a div with class main-page, nothing too scary. The real magic happens behind the scenes in that React will automagically update subtrees like these as properties change without touching the parts of the DOM that didn’t change.
This is important: React components update automatically when its props change but only if react is aware of the change! If you find a UI component doesn’t update, this is almost certainly the reason. I’ll go into this in later tutorials.
So React generates a bunch of divs and a list for us, that just leaves one last bit of code to look at: Object.keys(api).map((name, idx) => React.createElement(ListGroupItem, { key: idx }, name)
If you have been working with javascript before this is hopefully not too strange: Object.keys(api) retrieves a list of all the attributes in the api object. Since that object contains only functions, this is a list of the functions the api exposes. list.map() passes each element of a list through a function and generates a new list from its return values (the resulting list has the same length as the original). (args) => {} is the modern lambda syntax in javascript, so it defines an anonymous function for map to call.
So what this line does is take all the function names from the api and generate a “ListGroupItem” (aka “li”) for each.
If you’re like me, those nested React.createElement calls look rather nasty. React introduces a sligthly extended js file format that lets you write code like that in a more readable way:
class APIView extends React.Component {
render() {
const { api } = this.props;
return (
<MainPage>
<MainPage.Body>
<Panel>
<Panel.Body>
<ListGroup>
{Object.keys(api).map((name, idx) => <ListGroupItem key={idx}>{name}</ListGroupItem>)}
</ListGroup>
</Panel.Body>
</Panel>
</MainPage.Body>
</MainPage>
);
}
}
Not shorter but a lot more readable imho. However you can’t just import jsx, you need to preprocess it to turn it into usable javascript. See the next tutorial for that.
This wiki and the Vortex Readme document contains a lot of information, please take your time and read these instructions carefully.
We provide detailed changes for each Vortex release.
If you have any questions about Vortex usage or want to share some information with the Vortex community, please go to one of the following places:
- About
- Install
- Troubleshooting
- Troubleshooting
- Developers
- Troubleshooting
- Developers
- Valheim
- Bannerlord
- BepInEx
- How to test a game extension
- How to package a game extension
- How to upload an extension to Nexus
- How to submit a game extension for review
Warning
The below documentation has not been checked for quality since migrating to GitHub Wiki and the information contained is potentially out of date and\or repeated.
- Frequently Asked Questions
- Getting Started
- Deployment Methods
- Downloading from Nexus Mods
- Managing File Conflicts
- Managing your Load Order
- Managing Save Games
- Setting up Profiles
- Keyboard Shortcuts
- How to create mod installers
- External Changes
- The Vortex Approach to Load Order
- Moving Vortex to a new PC
- Modding Skyrim Special Edition with Vortex
- Modding Mount & Blade II: Bannerlord with Vortex
- Modding Monster Hunter: World with Vortex
- Modding The Witcher 3 with Vortex
- Modding Baldur's Gate 3 with Vortex
- Modding Stardew Valley with Vortex
- Modding Valheim with Vortex
- Error Messages
- Misconfigured Documents Folder
- .NET 6 Install Issues
- Downgrading Extensions
- Command Line Parameters
- Introduction to Vortex extensions
- Creating a game extension (JavaScript)
- Creating a theme
- Game detection
- Adding a main page
- Adding a load order page
- Building UI with Vortex and React
- Packaging an extension
- Introduction
- Packaging extensions
- Project management
- Harmony Patcher Exectuable
- Vortex Harmony Mod Loader
- Setting up your dev environment
- Creating a theme
- Creating a game extension