Simulating old Windows desktop programs with JavaScript and Tauri
Return to the times when buttons were not afraid of showing feelings.
Some time ago I stumbled upon a Windows 98 inspired CSS library called 98.css. I thought it was cool and wondered if there also existed one inspired by Windows XP - it does. I didn’t find one for Windows Vista, but someone did make one for Windows 7.
It is fun to look at the recreations of these design systems for nostalgia reasons, but also to marvel at how carefully each state of each component was thought out.
Another cool thing that I found recently is Tauri. It makes it easy to create desktop apps using web technologies for the front end. I thought it could be really fun to try and replicate a desktop window app using Tauri together with the aforementioned CSS libraries.
Creating a Tauri project
npm create tauri-app@latest
The CLI tool will ask to choose the preferred stack. I went with React and TypeScript. After installing dependencies with npm install, I ran the generated app with npm run tauri dev.
Adding stylesheets
98.css
With npm:npm install 98.css
Using CSS @import:
@import url("https://unpkg.com/98.css");
By importing the stylesheet in HTML:
<link rel="stylesheet" href="https://unpkg.com/98.css" />
Instead of using a CDN, the stylesheets can be also downloaded from GitHub and served directly.
XP.css
With npm:npm install xp.css
Using CSS @import:
@import url("https://unpkg.com/xp.css");
By importing the stylesheet in HTML:
<link rel="stylesheet" href="https://unpkg.com/xp.css" />
Instead of using a CDN, the stylesheets can be also downloaded from GitHub and served directly.
7.css
With npm:npm install 7.css
Using CSS @import:
@import url("https://unpkg.com/7.css");
By importing the stylesheet in HTML:
<link rel="stylesheet" href="https://unpkg.com/7.css" />
Instead of using a CDN, the stylesheets can be also downloaded from GitHub and served directly.
Making the window
Tauri provides the window API, which allows manipulating the window state, and the data-tauri-drag-region data attribute to drag the whole window by dragging the HTML element. This way I can mock a window, style it, and then add the functionality back.
import { appWindow } from "@tauri-apps/api/window";
import "98.css";
// import "xp.css";
// import "7.css";
const App = () => {
return (
<div className="window active">
<div className="title-bar" data-tauri-drag-region onDoubleClick={() => appWindow.toggleMaximize()}>
<div className="title-bar-text" data-tauri-drag-region>
{/* app title */}
</div>
<div className="title-bar-controls">
<button id="title-bar-minimize" aria-label="Minimize" onClick={() => appWindow.minimize()} />
<button id="title-bar-maximize" aria-label="Maximize" onClick={() => appWindow.toggleMaximize()} />
<button id="title-bar-close" aria-label="Close" onClick={() => appWindow.close()} />
</div>
</div>
<div className="window-body">
{/* your idea here */}
</div>
</div>
);
};
export default App;

This example is not going to work just yet without changes in tauri.conf.json.
In the allowlist I added:
"window": {
"all": false,
"close": true,
"hide": true,
"show": true,
"maximize": true,
"minimize": true,
"unmaximize": true,
"unminimize": true,
"startDragging": true
}
The buttons work! But the window still doesn’t look quite right. One more change is needed in tauri.conf.json, in windows:
"decorations": false,
"transparent": true

Cool, the native bar is gone. Now let’s fix the window size. Tauri uses WebKit which means that I can use WebKit CSS extensions. I think. It works on my computer. To prevent overflow, I made the wrapper .window display its content as flex.
:root, body, #root, .window, .window-body {
height: -webkit-fill-available;
}
.window {
display: flex;
flex-direction: column;
}

So that’s it! There’s the empty canvas now, ready to be painted with a masterpiece of your creation.