Skip to Content
DocumentationDevelopersBuild Code Components

Build Code Components

Code components extend Momen’s frontend with custom React and TypeScript. Build interfaces and interactions that are not available through built-in components, publish them as a component library, and import the library into a Momen project.

Common uses include data visualizations, maps, advanced forms, animations, and third-party frontend libraries. The zvm-code-context package connects a component to the host project’s data, user identity, GraphQL client, and runtime component tree.

Start a project

Before you begin, you should be comfortable with React, TypeScript, npm, and the Momen editor. You also need a working Node.js development environment.

Install the CLI

npm install --global momen-cli

List the commands available in your installed version:

momen --help

Sign in to Momen

momen signin <username-or-email> <password>

The CLI stores the local session used to create and publish code component projects.

Create a project

Run these commands from your working directory:

momen create my-components cd my-components npm install

create generates the local template and registers the corresponding code component project under the current Momen account.

Understand the project structure

Most development work takes place in src/components, src/graphql, resources, and package.json:

        • index.ts
        • Main.tsx
        • style.module.scss
      • index.ts
  • package.json
  • README.md
  • vite.config.ts
  • src/components contains component implementations and the exports included in the published library.
  • src/graphql contains GraphQL operations used by your components.
  • resources contains library and component icons, covers, and canvas previews.
  • package.json defines the library name, version, description, category, and supported platforms.
  • README.md explains the purpose and use of the library.

Build a component

Keep each component in its own directory. Both the directory and component names must begin with an uppercase letter. For a component named Counter:

src/components/Counter/ ├── Counter.tsx ├── index.ts └── style.module.scss

During publishing, the CLI reads three interfaces and converts their fields into configurable Momen properties, states, and events:

InterfacePurposeDeclaration
${ComponentName}PropDataInput data bound from Momen.Use a supported primitive or array type; fields may be optional.
${ComponentName}StateDataState the component can read, update, and expose to Momen.Use State<T>.
${ComponentName}EventFrontend events the component can trigger.Use EventHandler.

The Props interface types the React component itself. It is not a separate configuration interface parsed by the CLI.

Complete example

import { EventHandler, State } from 'zvm-code-context'; export interface CounterPropData { label: string; step?: number; } export interface CounterStateData { value?: State<number>; } export interface CounterEvent { onChange?: EventHandler; } export interface CounterProps { propData: CounterPropData; propState: CounterStateData; event: CounterEvent; } export function Counter({ propData, propState, event }: CounterProps) { const value = propState.value?.get() ?? 0; const increase = async () => { await propState.value?.set(value + (propData.step ?? 1)); event.onChange?.(); }; return ( <button type="button" onClick={increase}> {propData.label}: {value} </button> ); }

Export the component from its directory:

export * from './Counter';

Then register every component to publish in src/components/index.ts:

import { Counter } from './Counter'; export default { Counter, };

The publisher recognizes string, number, boolean, and arrays of these types. State fields use the corresponding State<T>, and event fields use EventHandler. The template also exports specialized date, time, and JSON types. The current CLI analysis result is authoritative for publishable types.

Use host APIs

Call useAppContext() inside a component to access the current Momen page, user identity, GraphQL client, and runtime component tree.

import { useAppContext } from 'zvm-code-context'; const ctx = useAppContext();

Navigate to a path in the host application.

ctx.navigate('/orders/10001');

The current signature is navigate(path). Build path and query parameters into the URL before calling it; a second configuration argument is not supported.

query

Send a GraphQL query or mutation to the project backend with the current host identity.

const response = await ctx.query( `query GetPosts($limit: Int!) { post(limit: $limit) { id title } }`, { limit: 10 } ); const posts = response.data?.post;

query returns the standard GraphQL JSON response. Handle both data and errors.

subscribe

Start a GraphQL subscription with the current host identity and handle each data update.

const subscription = ctx.subscribe( `subscription ListenPost($id: bigint!) { post_by_pk(id: $id) { id status } }`, { id: 100000000000001 }, (data) => { console.log(data.post_by_pk); } ); subscription.unsubscribe();

The callback receives the GraphQL data object. Call unsubscribe() when the component unmounts or no longer needs updates.

globalData

Read the current app-level variable object.

const locale = ctx.globalData?.locale;

globalData is the current value rather than a State object. To update app-level variables through runtime state, use discover('App').

pageData

Read or update the current page variable object.

const pageData = ctx.pageData.get(); await ctx.pageData.set({ ...pageData, selectedOrderId: 10001, });

pageData is a State object. Use get() and set() instead of mutating its properties directly.

apolloClient

Access the Apollo Client instance used by the host application. Use it when you need Apollo-specific features such as fetch policies, cache access, or manual refetching.

import GetPosts from '@/graphql/getPosts.gql'; const result = await ctx.apolloClient.query({ query: GetPosts, variables: { limit: 10 }, fetchPolicy: 'network-only', });

Prefer query and subscribe for ordinary GraphQL operations. Use apolloClient only when the additional Apollo behavior is necessary.

getLoggedInUserAuth

Get the current signed-in user’s authentication data asynchronously.

const auth = await ctx.getLoggedInUserAuth(); console.log(auth.userId); console.log(auth.userRoles);

The result contains userId, userToken, and userRoles. It may also include thirdPartyInfo for a third-party sign-in.

⚠️

userToken is the current user’s credential. Do not log it, send it to an untrusted service, or persist it in public storage.

component

Access the runtime component instance associated with the current code component. It exposes the current instance’s state, variables, runtime engine, and component-tree capabilities.

const currentComponent = ctx.component; const engine = currentComponent.engine;

Runtime component objects contain platform state. Before changing a value, use the field’s public get(), set(), or other supported methods instead of replacing object properties directly.

discover

Find a component instance in the host application by its runtime component ID.

const app = ctx.discover('App'); const appState = (app.state || app.variables).App_CustomState; const current = appState.get(); await appState.set({ ...current, locale: 'en-US', });

discover returns a runtime component instance, so its available fields depend on the target component type. Verify that the component ID and state exist before using them.

Configure the library

Review these package.json fields before publishing:

FieldDescription
nameComponent library name.
descriptionLibrary description.
versionVersion to publish. It must follow npm versioning and must not duplicate an existing release.
homepageOptional demo or introduction URL.
categoryComponent category, such as container, display, input, or others.
platformsSupported runtime platforms. Momen component libraries use WEB.

The resource directory supports the following files:

  • resources/icon.webp or resources/icon.svg for the library icon.
  • resources/{ComponentName}/icon.webp or .svg for a component icon.
  • resources/{ComponentName}/cover.webp or .svg for a component cover.
  • resources/{ComponentName}/canvas.webp or .svg for the canvas preview.
  • Root README.md for library documentation.
  • src/components/{ComponentName}/README.md for component documentation.

Debug components

Preview the build locally

npm run build npm run preview

The preview server uses port 6326 by default.

Connect to Momen real-time preview

The component library must have at least one published version before a Momen project can replace it with a local debug build.

  1. Run npm run preview.
  2. In another terminal, run npm run watch:build to rebuild after source changes.
  3. Open the debug entry in Momen real-time preview and select port 6326.
  4. Refresh real-time preview after changing the code.

Publish and import

Check the project

momen dryrun

This checks the project structure, component declarations, and build process before publishing.

Publish the library

momen publish

Update version in package.json before each release. To display detailed execution output, run:

momen publish --verbose

Use the library in Momen

Choose Import Component Library from the component panel and import the published library. You can then drag its components to the canvas and configure their properties, states, and events.

After publishing a new version, update the library version in every Momen project that uses it.

CLI commands

CommandPurpose
momen signin / signoutSign in to or out of Momen.
momen create <project-name>Create and register a code component project.
momen dryrunCheck whether the current project can be published.
momen publishBuild and publish a new version.
momen list <project-name>List published versions.
momen updateMigrate an older project to the current template structure. Commit or stash local changes first.
momen reinitRegister the current local project as a new project.
momen unpublish <version>Withdraw a published version.
momen delete [project-name]Delete a project; without a name, delete the project associated with the current directory.

reset, reinit, unpublish, and delete change the local project or remote release state. Confirm the target project and preserve your local code before running them.

Troubleshooting

ProblemResolution
The CLI reports that you are not signed inRun momen signin again.
The CLI cannot find a componentCheck the component directory, file names, three configuration interfaces, and the export in src/components/index.ts.
Properties, states, or events are missingConfirm that every field uses a supported type, then run momen dryrun --verbose to inspect parser errors.
The version already existsUpdate version in package.json and publish again.
Local changes do not appear in real-time previewConfirm that both watch:build and preview are running, then refresh real-time preview.
A GraphQL request failsInspect both data and errors in the response. See the Runtime API Reference for generated API structures.
Last updated on