
Research
Two Malicious Rust Crates Impersonate Popular Logger to Steal Wallet Keys
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
react-appkit
Advanced tools
The React meta-framework for rapidly building desktop apps.
React-AppKit is a robust meta-framework designed to help you quickly create, iterate on, and deploy desktop applications compatible with Windows, macOS and Linux.
Key features include:
Get started by running the create-app command:
npm create react-appkit-app
This will guide you through the process of setting up your new app.
You can immediately run your app by running the following command:
npm run dev
The app will launch shortly after, and any changes you make is automatically reloaded via HMR.
This section is under construction. 🚧
What is a window route? In React-AppKit, a window route is the main unit of UI container, similar to a "page" in a web app. You can find your window routes in the src/windows
directory.
Similar to other meta-frameworks, React-AppKit uses file-based routing. This means that each file in the src/windows
directory is treated as its own window route, which means you can either navigate to it in an existing window, or open it in a new one.
The default window can be found at src/windows/index.tsx
, which is automatically shown when your app is launched (though this can be changed).
Window routes run in a browser-like environment, meaning that any browser-compatible code can be used. This also means that you cannot use Node.js APIs directly, only via Node Actions (more on this later).
The path to the window route is determined by the path to the file under the src/windows
directory. Some examples:
src/windows/index.tsx
-> /
src/windows/about.tsx
-> /about
src/windows/settings/index.tsx
-> /settings
src/windows/settings/profile.tsx
-> /settings/profile
Window path can also include path parameters, for instance:
src/windows/users/:id.tsx
-> /users/123
, /users/456
, etc.You can use CSS Modules to style your window routes (by importing *.module.css
files), as well as use any other assets (images, fonts, etc.) by importing them in your typescript or css files.
If you want to apply a layout to a window or a group of windows, you can create a special file called [layout].tsx
in any directory under src/windows
.
Layout files allow you to wrap any window route with a common component, and look like this:
import type { LayoutProps } from '@react-appkit/sdk/layout';
export default function DefaultLayout({ children }: LayoutProps) {
return (
<div>
<h1>Title</h1>
{children}
</div>
);
}
Every window route is wrapped in the nearest layout file. That is, if you have a layout file at the same directory as a window route file, it's used; If not, the layout file in the closest parent directory is used.
Layouts are also where you should apply style to the window frame. In order to control the appearance of your window's frame, you can use the <Window />
components. These components expose various properties that allow to control the window's frame:
import type { LayoutProps } from '@react-appkit/sdk/layout';
import { Window } from '@react-appkit/sdk/window';
export default function DefaultLayout({ children }: LayoutProps) {
return (
<>
<Window>
<Window.Title>My App</Window.Title>
<Window.Dimensions
width={800}
height={600}
x="50%"
y="50%"
origin="center"
/>
</Window>
{children}
</>
);
}
For a full list of all the Window components, see the source.
React AppKit comes with a built-in navigation system, which allows you to do two main things:
You can access the navigation API via the useNavigation
hook, the <Link />
component, and via the window
SDK module.
When opening new windows, you can pass a "window channel". This identifier allows you to reuse the same window if already open. The main window is always channel _top
.
import { useNavigation, Link, usePathParams } from '@react-appkit/sdk/routing';
// Navigation
const navigation = useNavigation();
navigation.navigate('/about'); // Navigate to the about window
navigation.popup('/help'); // Opens a new window at /help
navigation.popup('/help', { target: 'secondary' }); // Opens a new window at /help, reuses the "secondary" channel if already open
navigation.close(); // Closes the current window
navigation.close({ target: 'secondary' }); // Closes the window at the "secondary" channel
// Link component
<Link to="/about">About</Link> // Navigates to the about window
<Link to="/about" target="_blank">About</Link> // Opens a new window at /about
<Link to="/help" target="secondary">Help</Link> // Opens a new window at /help, reuses the "secondary" channel if already open
// Window parameters
const params = usePathParams();
console.log(params.id); // if a there is a /users/:id.tsx file, and the current path is /users/123, the returned object will have a "id" property with the value "123"
Learn more about navigation: source.
Node actions are a way to write code that interacts with Node.js APIs. In order to create a Node action, create a new file in the src/actions
directory. The file should export any number of async functions, and can be imported by any other part of your app. Example:
// src/actions/config.ts
import fs from 'node:fs/promises';
export async function readConfig() {
const config = await fs.readFile('/config.json', 'utf-8');
return JSON.parse(config);
}
Similar to how Server Actions work in other frameworks, you can import and use Node actions from any window route and still expect it to run in the main Node process and have access to all Node.js APIs:
// src/windows/settings/index.tsx
import { readConfig } from '../../actions/config';
export default function Settings() {
const [config, setConfig] = useState(null);
useEffect(() => {
readConfig().then(setConfig);
}, []);
return <div>{config}</div>;
}
The SDK package is a collection of public runtime APIs to help you build your app.
Here is the complete list of modules:
@react-appkit/sdk/app
- Functions to control the app (e.g. quit
)@react-appkit/sdk/config
- Access the app's config file (src/app.config.ts
)@react-appkit/sdk/devtools
- The <Devtools />
component, which opens the dev tools console@react-appkit/sdk/dialog
- Functions to use native dialogs (e.g. alert
, confirm
, prompt
, file
)@react-appkit/sdk/global
- Access the global state@react-appkit/sdk/hotkeys
- The app's global hotkeys builder@react-appkit/sdk/layout
- Helper types to help you write Layout components@react-appkit/sdk/menu
- Components to help you build the application menu (if you want to use the menu system)@react-appkit/sdk/routing
- The useNavigation
hook, the <Link />
component, and other hooks related to navigation@react-appkit/sdk/tray
- Components to help you build the tray icon (if you want to use the tray system)@react-appkit/sdk/window
- The <Window />
component, and imperative API to control windowsReact AppKit provides a global state system, which allows you to share data between different parts of your app, regardless of which window or process it is in.
When used in a React component, the global state can be accessed via the useGlobalState
hook:
import { useGlobalState } from '@react-appkit/sdk/global';
export default function MyComponent() {
const [count, setCount] = useGlobalState('count', 0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Plus 1</button>
</div>
);
}
As you can see, the hook provides a state-like interface. It's also reactive, and will automatically re-render the component when the global state changes from any other part of the app.
From a non-react context, you can access the global state via imperative API:
import { setGlobalState, getGlobalState } from '@react-appkit/sdk/global';
const count = await getGlobalState('count') ?? 0;
await setGlobalState('count', count + 1);
Learn more about navigation: source.
If your app uses the tray system, you can create and control your own tray icon by creating a file called src/tray.tsx
.
The tray file should export a default component that uses the <Tray />
component to create the tray icon. For instance:
// src/tray.tsx
import { Tray, TrayMenu, TrayMenuItem } from '@react-appkit/sdk/tray';
import glyphPng from './assets/glyph.png';
export default function TrayIcon() {
return (
<Tray icon={glyphPng}>
<TrayMenu>
<TrayMenuItem.Button label="About" onClick={() => { /* ... */ }} />
<TrayMenuItem.Separator />
<TrayMenuItem.Button label="Quit" onClick={() => quit()} />
</TrayMenu>
</Tray>
);
}
A few notes:
TrayMenu
and TrayMenuItem
components.Learn more about the tray system: source.
If your app needs to use the platform's native menu system, you can create and control your own menu by creating a file called src/menu.tsx
.
The menu file should export a default component that uses the set of menu components to create the application menu. For instance:
// src/menu.tsx
import { ApplicationMenu, Menu, MenuItem } from '@react-appkit/sdk/menu';
export default function AppMenu() {
return (
<ApplicationMenu>
<Menu title="File">
<MenuItem.Button label="New" onClick={() => { /* ... */ }} />
<MenuItem.Button label="Open" onClick={() => { /* ... */ }} />
<MenuItem.Button label="Save" onClick={() => { /* ... */ }} />
<MenuItem.Separator />
<MenuItem.Button label="Quit" onClick={() => quit()} />
</Menu>
<Menu title="Edit">
<MenuItem.Button label="Cut" onClick={() => { /* ... */ }} />
<MenuItem.Button label="Copy" onClick={() => { /* ... */ }} />
<MenuItem.Button label="Paste" onClick={() => { /* ... */ }} />
</Menu>
</ApplicationMenu>
);
}
On both Windows and Linux, the menu appears in the top-left corner of the window frame. You can hide it on certain windows by including <Window.Menu visible={false} />
in your layout file.
On macOS, the menu is displayed in the top-left corner of the screen as long as your app is focused.
Learn more about the menu system: source.
Certain apps need to define global hotkeys, which are shortcuts that can be used to trigger actions in the app regardless of whether the app is focused. You can define global hotkeys by creating a file called src/hotkeys.ts
, using the hotkeys builder API and exporting its results as a default export:
// src/hotkeys.ts
import { hotkeys } from '@react-appkit/sdk/hotkeys';
export default hotkeys().addHotkey(['CmdOrCtrl', 'Shift', 'R'], () => {
console.log('Hello from React AppKit!');
});
Learn more about the hotkeys system: source.
If there's code that needs to run before the app is ready, you can define a startup function by creating a file called src/startup.ts
:
// src/startup.ts
export default async function () {
console.log('Booting up...');
}
This function is executed in the main process, before the app is ready and before any windows are shown.
This is a file that allows you to define the app's configuration. It's located at src/app.config.ts
:
// src/app.config.ts
import { appConfig } from '@react-appkit/sdk/config';
export default appConfig({
id: 'com.example.my-app',
displayName: 'My App',
buildTargets: ['mac', 'linux', 'win'],
});
Some of the properties are required:
id
: The app's unique identifier (used by the OS).displayName
: The app's display name (human-readable).buildTargets
: The platforms to build the app for.There are also some optional properties:
singleInstance
: Whether the app should be a single instance. If true, the app will refocus the existing window instead of opening a new one when the user opens the app more than once.openWindowOnStartup
: Whether the app should open the window on startup. If set to false, the app will start in the background; you can still open the window at any point by calling the createWindow
function.windowFrameType
: Whether the windows should use the platform's native frame, or a custom one (meaning that you design the frame as part of your Window or Layout components)Learn more about the app config: source.
Finally, to set the app's icon, simply add a file named src/icon.png
to your project. This file will be automatically recognized and used during build.
React AppKit comes with a built-in dev command, which allows you to run your app in dev mode and supports HMR. To start the dev server, run the following command:
npm run dev
You can build your app by running the following command:
npm run build
This will create a build of your app's source code in the dist
directory. Note: this does not create an executable, but rather the necessary files to run your app when running npm start
.
To create an executable, you can run the following command:
npm run pack
This will create an executable for your app in the dist/binaries
directory.
Our runtime provides a unified react-dom app that wraps user code with all the necessary providers to run in context of a React-AppKit app.
This includes:
react-router-dom
)All the routing information is collected in build time using Vite's builtin glob import functionality.
Whenever a new window is created, the wrapper tells the app to boot up from the specified route.
Node functions are collected in build time using Vite's builtin glob import functionality, and provided to the main process init function, which is in charge of registering them.
In each and every window, we run a preload script that initializes a bridge to the main process (using electron's native APIs). This bridge allows the window to invoke any Node Action, as well as access the global state system and other built-in APIs such as the Dialog and Window management systems.
Finally, when building the renderer bundle, we polyfill imports from the actions
directory to instead use the bridge. As a result, user code can import Node actions from any window route, get full types as if it was really imported, and still expect it to run in the main process and have access to all Node.js APIs without bundling the actual Node.js code into the renderer bundle.
We provide a set of components that directly interact with Electron's native tray and menu systems. These components are rendered in the main process using a custom renderer, which is currently based on react-nil
.
FAQs
Placeholder package
The npm package react-appkit receives a total of 430 weekly downloads. As such, react-appkit popularity was classified as not popular.
We found that react-appkit demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
Research
A malicious package uses a QR code as steganography in an innovative technique.
Research
/Security News
Socket identified 80 fake candidates targeting engineering roles, including suspected North Korean operators, exposing the new reality of hiring as a security function.