Registering custom functions

You can register custom JavaScript functions from your codebase and use them in Plasmic Studio. Once registered, they are available in the code editor wherever Plasmic accepts a dynamic value: text content, prop bindings, visibility conditions, and so on.

If you need to fetch or modify data from a remote source (like databases or API), check out the custom data queries page. Data queries are automatically exposed in the Plasmic data queries UI.

Use cases

Registered functions can be exposed in a few different places in Plasmic Studio, depending on the metadata you pass to registerFunction().

As code helpers

By default, any registered function is available in the code editor under the $$ namespace — for example $$.myFunc() or $$.funcNamespace.otherFunc(). You can use these wherever Plasmic accepts a dynamic value: text content, prop bindings, visibility conditions, and so on.

In the interactions

Set isMutation: true to show a registered function in the interactions UI. This is the right choice for functions that perform an action, such as writing data or triggering a workflow. When registering the function, you can specify the parameters it takes, and these will be automatically turned into input fields in the interaction configuration UI.

As custom data queries

If you set isQuery: true when registering a function, it also shows up in the Data Queries section of the Page Data tab. This is the right choice for functions that fetch or compute data which components depend on — API calls, database reads, or computed datasets. Query results are then accessible in the page via $q.myQueryName, and they can be named, cached, and reused across components in the page.

Read more about custom data queries here.

If neither isQuery nor isMutation is set, the function is only available in custom code expressions through $$.

Example: helper functions

You can register standard JavaScript functions from your codebase to later use them in Plasmic Studio code editor. By default, any registered function is available in the code editor under the $$ namespace — for example $$.myFunc() or $$.funcNamespace.otherFunc().

Copy
import { parseData } from '../data-utils';
// Basic usage
PLASMIC.registerFunction(parseData, {
name: 'parseData'
});
import { isEven } from 'some-utility-package';
// Register with param and return value documentation (types, description)
PLASMIC.registerFunction(isEven, {
name: 'isEven',
params: [
{
name: 'x',
type: 'number',
description: 'The value to test its evenness'
}
],
returnValue: {
type: 'boolean',
description: 'Whether `x` is an even number'
}
});
import { filterData } from '../data-utils';
// Add custom typescript declaration for complex types
PLASMIC.registerFunction(filterData, {
name: 'filterData',
description: `Filters the data.
@param data The data to filter
@param opts The options for filtering`,
typescriptDeclaration: `<T>(
data: T[],
opts?: {
/** Maximum number of elements to return */
limit?: number;
/** Options for sorting the data */
sort?: {
field: string;
order: "asc" | "desc";
}
}
): T[]`
});

Example: async functions

You can register async functions to execute operations that need some time to complete, like fetching or mutating data from an API. This is useful for operations that require server-side processing, like generating hashes, accessing server secrets, or server-side logging.

Since the function can be executed both on the server (during SSR) and the client, you can’t use client-side variables like $state or window.

The registerFunction call stays the same:

Copy
'use server';
import { logToServer } from '@/utils/logger';
export const serverLog = async (message: string) => {
try {
await logToServer(message);
return { success: true };
} catch (error: unknown) {
return { error: 'Logging failed' };
}
};

And then register it to Plasmic in the separate file:

Copy
import { serverLog } from '@/functions/serverLog';
PLASMIC.registerFunction(serverLog, {
name: 'serverLog',
isMutation: true,
displayName: 'Server Logger',
description: 'Logs a message to the server securely.',
params: [
{
type: 'string',
name: 'message',
description: 'The message to log.'
}
]
});

You can then use it in Studio, for instance, inside an interaction just like synchronous functions.

registerFunction API

registerFunction() is called with the function to be registered, along with an object with these fields:

FieldRequired?Description
nameYesThe JavaScript name of the function.
displayNameNoA user-friendly name for the function, which can be used in the Plasmic UI.
namespaceNoA namespace for organizing groups of functions. It’s also used to handle function name collisions. If a function is registered with a namespace, it’ll be used whenever accessing the function.
descriptionNoDocumentation for the registered function.
paramsNoAn array containing the list of parameters names the function takes. Optionally they can also be registered with the expected param types.
returnValueNoAn object with the return value information. It can include the return value type and description.
typescriptDeclarationNoTypescript function declaration. If specified, it ignores the types provided by params and returnValue.
importPathYes if using codegenThe path to be used when importing this function in the generated code. It can be the name of the npm package that contains the component (like lodash), or the path to the file in the project (relative to the root directory, where the plasmic.json file is located).
isDefaultExportNoIf true, then this function is the default export from importPath.
isQueryNoIf true, this function is available in the Data Queries section. Use this for functions that fetch data or compute values that components depend on.
isMutationNoIf true, this function is available in interactions. Use this for functions that perform actions, such as writes or workflow triggers.
fnContextNoA function that takes the function arguments and returns a data key and a fetcher function. See usage example on the custom data queries document. The data key is used to cache the result of the fetcher, and should only include the arguments that are used to fetch the data. The result of the fetcher will be used as the context of the function in studio and should return a promise.

Is this page helpful?

NoYes