# How to Add a New Page Component to the Celeris Web Application

> Learn how developers add a new page component to the Celeris Web application. Extend the admin panel by creating a Vue component and registering it as a typed route module.

- Repository: [Kirk Lin/celeris-web](https://github.com/kirklin/celeris-web)
- Tags: how-to-guide
- Published: 2026-03-05

---

**Developers extend the Celeris Web admin panel by creating a Vue single-file component in the pages directory and registering it as a typed route module in the routes folder, which the router auto-discovers via file glob patterns.**

Celeris Web is a modern Vue 3 admin dashboard framework that implements file-based route conventions to streamline page registration. When you need to add a new page component to the Celeris Web application, the framework's modular router system eliminates manual route imports by automatically scanning specific directories. This guide walks through creating a page component, registering its route definition, and configuring navigation metadata using the actual source architecture from the `kirklin/celeris-web` repository.

## Create the Vue Page Component

Start by creating the user interface for your new page. The convention places page components in `apps/admin/src/pages/` using a directory structure that matches your desired URL path.

1. **Create the directory and file** – Add a new folder under `apps/admin/src/pages/` (e.g., `hello-world/`) with an [`index.vue`](https://github.com/kirklin/celeris-web/blob/main/index.vue) file.

2. **Use the setup script pattern** – Follow the existing codebase style with `<script setup lang="ts">` and `defineOptions` for the component name.

3. **Wrap with PageWrapper** – Import and use the `PageWrapper` component to maintain consistent layout padding and styling.

```vue
<!-- apps/admin/src/pages/hello-world/index.vue -->
<script setup lang="ts">
import { defineOptions } from "vue";

defineOptions({ name: "HelloWorldPage" });
</script>

<template>
  <PageWrapper>
    <h1>Hello, Celeris Web!</h1>
    <p>This is a brand-new page component.</p>
  </PageWrapper>
</template>

<style scoped></style>

```

Reference the **Dashboard** page at [`apps/admin/src/pages/dashboard/index.vue`](https://github.com/kirklin/celeris-web/blob/main/apps/admin/src/pages/dashboard/index.vue) for production-ready patterns including data fetching and state management.

## Register a Route Module

The router automatically discovers route definitions by importing all TypeScript files in `apps/admin/src/router/routes/modules/`. You do not need to manually import your new route into the router configuration.

Create a new TypeScript file in that directory that exports a `RouteRecordRaw` object. The `loadRoutesFromModules` utility in [`packages/web/utils/src/router.ts`](https://github.com/kirklin/celeris-web/blob/main/packages/web/utils/src/router.ts) processes these files automatically.

```ts
// apps/admin/src/router/routes/modules/hello-world.ts
import type { RouteRecordRaw } from "vue-router";
import { LAYOUT } from "~/router/constant";

const helloWorld: RouteRecordRaw = {
  path: "/hello-world",
  name: "HelloWorldRoot",
  component: LAYOUT,
  redirect: "/hello-world/index",
  meta: {
    title: "routes.helloWorld.helloWorld",
    icon: "i-mdi-emoticon-happy",
    orderNumber: 100,
  },
  children: [
    {
      path: "index",
      name: "HelloWorld",
      component: () => import("~/pages/hello-world/index.vue"),
      meta: {
        title: "routes.helloWorld.helloWorld",
        icon: "i-mdi-emoticon-happy",
        shouldAffixToNavBar: true,
      },
    },
  ],
};

export default helloWorld;

```

**Key implementation details:**

- **LAYOUT** – Imported from `~/router/constant`, this wrapper component provides the common admin UI shell including headers and sidebars.
- **Lazy loading** – Use `() => import()` for the component property to enable code-splitting and improve initial load performance.
- **Meta fields** – The `title` supports i18n keys, `icon` uses the project's iconify preset, and `orderNumber` controls the sidebar menu sort order.

The automatic discovery happens in [`apps/admin/src/router/routes/index.ts`](https://github.com/kirklin/celeris-web/blob/main/apps/admin/src/router/routes/index.ts) via `import.meta.glob`:

```ts
const modules = import.meta.glob<{ default: any }>("./modules/**/*.ts", { eager: true });
const routeModuleList: RouteRecordRaw[] = loadRoutesFromModules(modules);

```

## Configure Sidebar Navigation

To display the page in the left-hand navigation menu, provide the required **meta** fields in your route definition. The menu system in [`apps/admin/src/router/menus/index.ts`](https://github.com/kirklin/celeris-web/blob/main/apps/admin/src/router/menus/index.ts) reads the router's meta data to generate the sidebar structure automatically.

- Set `title` with an i18n key or string for the menu label.
- Set `icon` using the project's icon naming convention (e.g., `i-mdi-emoticon-happy`).
- Set `orderNumber` to position the item relative to other routes.

To hide a page from the menu while keeping it accessible via URL, add `shouldHideInMenu: true` to the route's meta object. To pin it to the navigation bar, use `shouldAffixToNavBar: true`.

## Verify the New Page

Start the development server to test your implementation:

```bash
pnpm run dev

```

Navigate to `http://localhost:8888/#/hello-world` to confirm the page renders within the layout shell. Check that:

- The component loads without console errors.
- The sidebar displays your new entry (unless hidden).
- The URL routing resolves correctly.

## Summary

- **Create** the Vue SFC in `apps/admin/src/pages/[page-name]/index.vue` using the setup script pattern.
- **Register** the route by exporting a `RouteRecordRaw` object from a new file in `apps/admin/src/router/routes/modules/`.
- **Leverage** the auto-discovery system in [`packages/web/utils/src/router.ts`](https://github.com/kirklin/celeris-web/blob/main/packages/web/utils/src/router.ts) via `loadRoutesFromModules` to avoid manual imports.
- **Configure** navigation visibility using meta fields like `title`, `icon`, `orderNumber`, and `shouldHideInMenu`.
- **Use** `LAYOUT` from `~/router/constant` to maintain consistent UI wrapping.

## Frequently Asked Questions

### Do I need to manually import new route files into the router configuration?

No. The system uses `import.meta.glob` in [`apps/admin/src/router/routes/index.ts`](https://github.com/kirklin/celeris-web/blob/main/apps/admin/src/router/routes/index.ts) to eagerly import all `.ts` files under `apps/admin/src/router/routes/modules/`. The `loadRoutesFromModules` function in [`packages/web/utils/src/router.ts`](https://github.com/kirklin/celeris-web/blob/main/packages/web/utils/src/router.ts) automatically processes these into the `asyncRoutes` array without requiring manual imports.

### What is the purpose of the `LAYOUT` constant in route definitions?

**`LAYOUT`** (exported from [`apps/admin/src/router/constant.ts`](https://github.com/kirklin/celeris-web/blob/main/apps/admin/src/router/constant.ts)) is the root wrapper component that renders the common admin interface structure, including the sidebar navigation and header. Assigning it to the parent route's `component` property ensures your page renders within this shell, while child routes lazy-load the specific page components.

### How do I prevent a page from appearing in the sidebar menu?

Add `shouldHideInMenu: true` to the route's `meta` object. The menu generation logic in [`apps/admin/src/router/menus/index.ts`](https://github.com/kirklin/celeris-web/blob/main/apps/admin/src/router/menus/index.ts) filters out routes with this flag set, making the page accessible only via direct URL or programmatic navigation while keeping it out of the navigation UI.

### Can I organize route modules into subdirectories?

Yes. The glob pattern `"./modules/**/*.ts"` recursively searches all subdirectories within `apps/admin/src/router/routes/modules/`. You can organize routes by feature (e.g., [`modules/users/profile.ts`](https://github.com/kirklin/celeris-web/blob/main/modules/users/profile.ts), [`modules/users/settings.ts`](https://github.com/kirklin/celeris-web/blob/main/modules/users/settings.ts)) and the router will discover them automatically.