crudy
    FeaturesUse CasesDocumentationPricingAboutContact
    Get started free
    Documentation
    • Introduction
    • Installation
    • Quickstart
    • CLI Reference
    • Overview
    • Core Packages
    • App Structure
    • Modules & Routes
    • Module Anatomy
    • Backend Module
    • Frontend Module
    • Quotas
    • Full Example
    • Overview
    • Docker
    • Environment Variables
    • Licensing
    Modules

    Frontend Module

    Defining a FrontendModule: pages, nav, slots.

    A FrontendModule declares the UI a module contributes to a Crudy app: pages, sidebar items, settings tabs, custom login methods, an optional home page, and slot contributions into other modules' pages.

    Shape

    ts
    export interface FrontendModule {
        manifest: ModuleManifest;
        navItems?: NavItemDefinition[];
        settingsTabs?: SettingsTabDefinition[];
        routes?: RouteDefinition[];
        defaultRoute?: string;
        HomePage?: ComponentType;
        RootComponent?: ComponentType;
        loginMethods?: LoginMethodDefinition[];
        slotContributions?: Partial<Record<SlotName, ComponentType<SlotContext>>>;
    }

    manifest

    Identity. The id must match the backend half's manifest.id.

    ts
    manifest: { id: 'tasks', name: 'Tasks', version: '0.1.0' }

    navItems

    Sidebar entries the module wants in the app shell.

    ts
    import { ListChecks } from 'lucide-react';
     
    navItems: [
        { href: '/tasks', label: 'Tasks', icon: ListChecks },
    ]

    hiddenByDefault ships the item to the hidden bucket in user preferences. divider inserts a separator above the item.

    settingsTabs

    Tabs added to the framework's Settings page. Each tab declares a morbac permission required to render; users without the permission do not see the tab.

    ts
    settingsTabs: [
        {
            id: 'tasks-defaults',
            label: 'Task Defaults',
            permission: ['manage', 'tasks'],
            component: TaskDefaultsTab,
        },
    ]

    The component receives token and orgIds. Use these to call the data API and to filter by the current org selection.

    routes

    Pages the module contributes. Mounted under the framework's catch-all route.

    ts
    routes: [
        { path: '/tasks',       Component: TaskListPage },
        { path: '/tasks/new',   Component: NewTaskPage, quota: { key: 'records' } },
        { path: '/tasks/about', Component: AboutTasksPage, public: true },
    ]

    Non-public routes receive ModulePageProps: token, userId, userName, userEmail, allOrgs, effectiveOrgIds, checkPermission, and the host UI primitives (AppShell, Card, Button, ...). Use the host primitives so the page respects the app's theme, density, and layout.

    When quota: { key: 'records' } is set, the framework checks the current org's remaining quota for that key before rendering. If the cap is reached, the page renders a quota-exceeded state instead of the component.

    Public routes receive no props. Use them for marketing pages, docs, or anything that must work without authentication.

    defaultRoute

    When set, the framework treats this path as the module's landing page. Used for navigation fallbacks.

    ts
    defaultRoute: '/tasks'

    HomePage

    Replaces the framework's home page when the module is registered. Only one module should set this per app; if more than one does, the last-wins behavior is undefined. The website module uses this to render the marketing landing page in the example app.

    RootComponent

    A component rendered once near the top of the React tree, inside CrudyProviders but above the routed pages. Use it for module-wide React context that other module pages need to consume.

    loginMethods

    Custom alternatives to the framework's password login form. Each entry contributes a button or form fragment to the login page.

    ts
    loginMethods: [
        { id: 'oidc', Component: OidcLoginButton },
    ]

    The component receives an optional orgHint so it can pre-select the right tenant.

    slotContributions

    A way to inject UI into named extension points exposed by other modules or by the framework. The framework defines a few well-known slot names; modules can also define their own.

    ts
    slotContributions: {
        'user.detail.actions': InviteToTeamButton,
        'org.detail.actions':  ProvisionTaskSpaceButton,
    }

    The component receives SlotContext: orgId, token, userId. Use these to call the data API. Slot components must respect the host theme and remain hidden when the current user lacks permission.

    Minimal example

    ts
    import type { FrontendModule } from '@crudy/frontend';
    import { ListChecks } from 'lucide-react';
    import { TaskListPage } from './pages/task-list';
     
    export const TasksFrontend: FrontendModule = {
        manifest: { id: 'tasks', name: 'Tasks', version: '0.1.0' },
        navItems: [{ href: '/tasks', label: 'Tasks', icon: ListChecks }],
        routes:   [{ path: '/tasks', Component: TaskListPage }],
    };
    PreviousBackend ModuleNext Quotas
    crudy

    Build internal tools your teams actually use. Powered by a framework built for developers.

    Product

    • Features
    • Use Cases
    • Pricing

    Company

    • About
    • Contact

    © 2026 Crudy. All rights reserved.

    crudy.fr