Mod is tightly integrated with Joystick, the full-stack JavaScript framework built by Mod's creator, CheatCode.
In order to integrate with Joystick, you only need to copy files from the mod.zip
file you downloaded from the Mod App into your Joystick app. Behind the scenes, Joystick will automatically try to detect Mod, and if it's present, load its CSS and JS during server-side rendering (SSR).
Joystick will also handle user theme preferences automatically and gives you the ability to set a global default theme as a fallback.
Loading Mod's CSS, JavaScript, and Font
To start installing Mod in your app, first, you'll want to copy the required Mod files into your app. Use the table below to know where files should go:
Paths for Plus Users
If you've purchased a copy of Mod Plus, you will want to use the plus
file variants (e.g., mod-light-plus.min.css
) below.
Type | File in mod(-plus).zip | Target path in app | What is it? |
---|---|---|---|
File | mod_version.txt | private/mod/mod_version.txt | A file that tells Joystick which version of Mod your app is using (free or plus). |
Folder | components/ | private/mod/components | The CSS for individual Mod components. Used for tree-shaking Mod during server-side rendering (SSR). |
Folder | globals/ | private/mod/globals | Global CSS files for Mod. Used for tree-shaking Mod during server-side rendering (SSR). |
File | mod-light(-plus).min.css | private/mod/mod-light(-plus).min.css | The light-themed version of Mod. |
File | mod-dark(-plus).min.css | private/mod/mod-dark(-plus).min.css | The dark-themed version of Mod. |
File | mod(-plus).iife.min.js | public/mod(-plus).iife.min.js | The IIFE version of the JavaScript for Mod's interactive components. Use this if you want to load Mod's JavaScript globally in your app. |
File | mod(-plus).esm.min.js | lib/mod(-plus).esm.min.js | The ESM version of the JavaScript for Mod's interactive components. Use this if you want to load Mod's JavaScript incrementally in your app. |
File | fonts/lucide.woff2 | public/fonts/lucide.woff2 | The icon font used by Mod, Lucide. |
File | fonts/mod-brand-icons.woff2 | public/fonts/mod-brand-icons.woff2 | The icon font for brand logos used by Mod. |
Once you've copied all of the required files into your app, the last step is to add Mod's font, Inter, to your app's index.html
file:
index.html
<!doctype html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
<title>App</title>
<meta name="description" content="A new Joystick app.">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#FFCC00">
<link rel="apple-touch-icon" href="/apple-touch-icon-152x152.png">
<link rel="stylesheet" href="/_joystick/index.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap" rel="stylesheet">
<link rel="manifest" href="/manifest.json">
${css}
</head>
<body>
<div id="app"></div>
</body>
</html>
Above, we have three <link>
tags from Google that handle pre-connection to their CDN and include the CSS for the font.
With all of that in place, Mod is ready to use.
Accessing Mod's JavaScript via components
If Mod is detected in your app (relative to the paths described in the table above), Joystick will automatically load the version of Mod's JavaScript into your app (based on the value inside of the private/mod_version.txt
file—e.g., if this contains plus
, the JavaScript for Mod Plus will be loaded).
Now, in your UI, all components will have access to Mod's JavaScript via the component instance at instance.mod
.
import joystick from '@joystick.js/ui';
const Login = joystick.component({
lifecycle: {
on_mount: (instance = {}) => {
instance.mod.password_input();
},
},
render: () => {
return `
<form class="login">
<div class="mod-form-input">
<label class="mod-input-label">Email Address</label>
<input type="email" name="email_address" class="mod-input" placeholder="Email Address" />
</div>
<div class="mod-form-input">
<label class="mod-input-label">Password</label>
<div class="mod-password-input-show-hide">
<input type="password" class="mod-input" name="password" placeholder="Password" />
<i class="mod-icon-eye"></i>
</div>
</div>
</form>
`;
},
});
export default Login;
Above, to enable the interactive behavior on the mod-password-input
element, inside of our lifecycle.on_mount()
method, we access instance.mod.password_input()
which attaches the JavaScript for the mod-password-input
element.
Loading JavaScript Manually
Loading Mod's ESM JavaScript
While the above approach will work for most use cases, if you need to load Mod's JavaScript manually, you can import it from the lib
folder at the root of your app like any other JavaScript module (assuming .esm.js
variant usage).
Not Recommended
The following approach is not recommended as Joystick will still attempt to load Mod's JavaScript automatically in your app (i.e., doing the below will result in the same JavaScript being loaded for the functions you import on the client twice).
ui/pages/index/index.js
import joystick from '@joystick.js/ui-canary';
import { command_palette } from '../../../lib/mod(-plus).esm.min.js';
const Index = joystick.component({
lifecycle: {
on_mount: () => {
command_palette();
},
},
render: ({ props, state, data, methods }) => {
return `
<div class="mod-command-palette">
<!-- HTML for Mod's command palette component -->
</div>
`;
},
});
export default Index;
Up top, we add an import for the command_palette()
method from Mod's JavaScript file. On our component, we define the on_mount
lifecycle method (this runs as soon as our component is mounted on screen), and inside, call to the command_palette()
method.
Loading Mod's IIFE JavaScript
Optionally (though not recommended), you can load the .iife.js
variant of Mod's JavaScript in your app's index.html
file at the root of your app.
Not Recommended
The following approach is not recommended as Joystick will still attempt to load Mod's JavaScript automatically in your app (i.e., doing the below will result in the same JavaScript being loaded on the client twice).
index.html
<!doctype html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
<title>App</title>
<meta name="description" content="A new Joystick app.">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#FFCC00">
<link rel="apple-touch-icon" href="/apple-touch-icon-152x152.png">
<link rel="stylesheet" href="/_joystick/index.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap" rel="stylesheet">
<script src="/mod(-plus).iife.min.js"></script>
<link rel="manifest" href="/manifest.json">
${css}
</head>
<body>
<div id="app"></div>
</body>
</html>
Above, we've added a <script>
tag pointing to Mod's IIFE JavaScript file that you copied over to the public
folder in your app earlier. To access the JavaScript at a component-level, we can do the following:
ui/pages/index/index.js
import joystick from '@joystick.js/ui-canary';
const Index = joystick.component({
lifecycle: {
on_mount: () => {
if (window.mod) {
window.mod.command_palette();
}
},
},
render: ({ props, state, data, methods }) => {
return `
<div class="mod-command-palette">
<!-- HTML for Mod's command palette component -->
</div>
`;
},
});
export default Index;
Here, because we loaded Mod globally, we expect window.mod
to be defined. On our component, we define the on_mount
lifecycle method (this runs as soon as our component is mounted on screen), and inside, first check if window.mod
is defined and if it is, call to our component's JavaScript method window.mod.command_palette()
.
Setting a Default Theme
By default, Joystick will default to Mod's light
theme in your app. If you'd like to override this, in your index.server.js
file, you can specify the default theme via your app's options:
index.server.js
import joystick from "@joystick.js/node-canary";
joystick.app({
mod: {
default_theme: 'dark',
},
routes: { ... },
});
Above, we set the mod
object in our app options to an object with a default_theme
key and a value equal to the Mod theme that we'd like to default our app to (here, dark
).
By default, Joystick will use this theme for your app if the current user does not have a theme
cookie defined in their browser (setting this cookie can be done wherever you'd like in your app's UI).
The preference order for which theme gets applied to your app is as follows:
- If the user has a
theme
cookie defined, use that. - If there's no
theme
cookie, fall back to themod.default_theme
(what we've shown above) if it's defined. - If there's no
theme
cookie and nomod.default_theme
set, fall back tolight
.
Using Tree-Shaking
Experiemental: Use With Caution
This approach is best reserved for apps that need (or want) to critically reduce page size. Keep in mind that if you use this approach, parts of your UI may look broken if you haven't specified their component name in the mod.components
array.
Using Mod's full CSS file can be helpful to speed up the development process, however, this can add unnecessary weight to pages as they're likely to use only a few of Mod's components.
Because your app can use conditional logic (in a Joystick app, HTML wrapped in a when()
render method) that prevents Joystick from "seeing" all of the Mod components in use in your app, as an alternative, Joystick offers the ability to specify which component's to load CSS for at the route level:
index.server.js
import joystick from "@joystick.js/node-canary";
joystick.app({
mod: {
default_theme: 'dark',
},
routes: {
'/': (req = {}, res = {}) => {
res.render('ui/pages/index/index.js', {
layout: 'ui/layouts/app/index.js',
mod: {
components: [
'alert',
'button',
'command-palette',
...other components in use...
],
},
});
},
},
});
Above, for our hypothetical /
index route, to the options object for our res.render()
call, we've added a mod
object with a components
array containing the names of Mod components we'd like Joystick to load the CSS for. Any component used on the page that is not in this array will appear unstyled.