Concepts

Component Types

The different roles and uses for a component in a Joystick app.

Nested inside of Joystick's /ui folder, by default, you will find three different folders:

  • ui/layouts
  • ui/pages
  • ui/components

Each of these folders represents a type of component that's used in your UI. Though all components in a Joystick app are defined using the same joystick.component() method, their purpose dictates where they live within your project structure.

Layouts

Layout components in a Joystick app are intended to be global components that render always-visible UI (e.g., a navigation bar and a footer) along with the current page. While they're typically used exclusively for rendering a page within a consistent "frame," they can be as simple or as advanced as your app requires.

ui/layouts/app/index.js

import joystick from "@joystick.js/ui";

const App = joystick.component({
  render: ({ props, component }) => {
    return `
      <div>
        ${component(props.page, props)}
      </div>
    `;
  },
});

export default App;

Above, we have the default App layout component created for you when you run joystick create <app-name> via the CLI. Here, we use the component() render method, anticipating a props.page value representing the current page being rendered into the layout. We also pass the props passed to the layout down to the page the layout is rendering.

Behind the scenes, that props.page value is automatically set by Joystick when using the res.render() method inside of one of your routes:

index.server.js

import joystick from "@joystick.js/node";

joystick.app({
  routes: {
    "/": (req = {}, res = {}) => {
      res.render("ui/pages/index/index.js", {
        layout: "ui/layouts/app/index.js",
      });
    },
  },
});

Above, because we've passed the layout option to res.render(), when this route is visited by a user, Joystick will automatically render that layout component (ui/layouts/app/index.js) and pass the component defined at ui/pages/index/index.js to it as props.page.

Inside of the layout component then, we take this prop and pass it to the component() render method because we expect it to contain an instance of a page component that we want to render into our layout.

Pages

A page component in a Joystick app represents a single page or "screen" in your UI. A profile page, a dashboard, a settings page, etc. A page can contain anything you'd like: static content, interactive elements—whatever. A page can be completely self-contained, or, import other components to render into itself.

Like we showcased above, a page is rendered via the res.render() method from one of your routes (passed as the first argument to that method):

index.server.js

import joystick from "@joystick.js/node";

joystick.app({
  routes: {
    "/": (req = {}, res = {}) => {
      res.render("ui/pages/index/index.js", {
        layout: "ui/layouts/app/index.js",
      });
    },
  },
});

A page can be rendered by itself, or—as the example shows above—within a layout.

Components

Any component that isn't a layout or page in a Joystick app is just considered a generic component. These are typically standalone components that are composed into your layouts, pages, or other components (e.g., a navbar component that's rendered inside of your layout component). Similar to pages, these can contain any UI or functionality you wish.