logologo
Get Started
Guide
Development
Plugins
API
English
简体中文
Get Started
Guide
Development
Plugins
API
English
简体中文
logologo
Overview

Blocks

Overview

Data Blocks

Table
Form
Details
List
Grid Card
Chart

Filter Blocks

Form

Other Blocks

Action Panel
Iframe
Reference block
Markdown
JS Block

Block Settings

Data Scope
Layout
Block Linkage Rules
Field Linkage Rules
Sorting Rules
Block Deletion
Block Title

Fields

Overview

Generic Settings

Table Column
Detail Form Item
Filter Form Item
Form Item

Specific Settings

Date
File Manager
Sub-form
Select
Picker
Sub-table
Sub-detail
Title
JS Field
JS Item
JS Column

Field Settings

Default Value
Field Label
Show Label
Field Tooltip
Data Scope
Field Component
Number Format
Pattern
Required
Title Field
Validation Rules
Association Field

Actions

Overview

Action Settings

Edit Button
Double Check
Assign Values
Bind Workflow
Edit Popup
Action Linkage Rules

Action Types

Add New
View
Delete
Edit
Import
Import Pro
Export
Export Pro
Export Attachments
Filter
Link
Pop-up
Refresh
Submit
Trigger Workflow
Update Record
Bulk Update
JS Action
Action Permissions

Advanced

Linkage Rules
Event Flow
Variables
RunJS
Previous PageMarkdown
Next PageData Scope

#JS Block

#Introduction

The JS Block is a highly flexible "custom rendering block" that allows you to write JavaScript directly to generate interfaces, bind events, call data APIs, or integrate third-party libraries. It is suitable for personalized visualizations, temporary experiments, and lightweight extension scenarios that are difficult to cover with built-in blocks.

#Runtime Context API

The JS Block's runtime context has common capabilities injected and can be used directly:

  • ctx.element: The DOM container of the block (safely wrapped as ElementProxy), supporting innerHTML, querySelector, addEventListener, etc.
  • ctx.requireAsync(url): Asynchronously loads an AMD/UMD library by URL.
  • ctx.importAsync(url): Dynamically imports an ESM module by URL.
  • ctx.openView: Opens a configured view (popup/drawer/page).
  • ctx.useResource(...) + ctx.resource: Accesses data as a resource.
  • ctx.i18n.t() / ctx.t(): Built-in internationalization capability.
  • ctx.onRefReady(ctx.ref, cb): Renders after the container is ready to avoid timing issues.
  • ctx.React / ctx.ReactDOM / ctx.antd: Supports JSX. You can write JSX directly in the editor, and it will be rendered by ctx.ReactDOM.
  • ctx.render(vnode): Renders a React element, HTML string, or DOM node to the default container ctx.element. Multiple calls will reuse the same React Root and overwrite the container's existing content.

#Adding a Block

You can add a JS Block to a page or a popup.

jsblock-add-20251029

#Editor and Snippets

The JS Block's script editor supports syntax highlighting, error hints, and built-in code snippets (Snippets), allowing you to quickly insert common examples such as rendering charts, binding button events, loading external libraries, rendering React/Vue components, timelines, information cards, etc.

  • Snippets: Opens the list of built-in code snippets. You can search and insert a selected snippet into the code editor at the current cursor position with one click.
  • Run: Directly runs the code in the current editor and outputs the execution logs to the Logs panel at the bottom. It supports displaying console.log/info/warn/error, and errors will be highlighted with links to the specific row and column.

jsblock-toolbars-20251029

Additionally, you can directly summon the AI employee "Frontend Engineer · Nathan" from the top-right corner of the editor. Nathan can help you write or modify scripts based on the current context. You can then "Apply to editor" with one click and run the code to see the effect. For details, see:

  • AI Employee · Nathan: Frontend Engineer

#Runtime Environment and Security

  • Container: The system provides a secure DOM container ctx.element (ElementProxy) for the script, which only affects the current block and does not interfere with other areas of the page.
  • Sandbox: The script runs in a controlled environment. window/document/navigator use secure proxy objects, allowing common APIs while restricting risky behaviors.
  • Re-rendering: The block automatically re-renders when it is hidden and then shown again (to avoid re-executing the initial mount script).

#Common Usage (Simplified Examples)

#1) Render React (JSX)

const { Button } = ctx.antd;
ctx.render(
  <div style={{ padding: 12 }}>
    <Button type="primary" onClick={() => ctx.message.success(ctx.t('Clicked!'))}>
      {ctx.t('Click')}
    </Button>
  </div>
);

#2) API Request Template

const resp = await ctx.api.request({ url: 'users:list', method: 'get', params: { pageSize: 10 } });
ctx.message.success(ctx.t('Request finished'));
console.log(ctx.t('Response data:'), resp?.data);

#3) Load ECharts and Render

const container = document.createElement('div');
container.style.height = '360px';
container.style.width = '100%';
ctx.element.replaceChildren(container);
const echarts = await ctx.requireAsync('https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js');
if (!echarts) throw new Error('ECharts not loaded');
const chart = echarts.init(container);
chart.setOption({ title: { text: ctx.t('ECharts') }, xAxis: {}, yAxis: {}, series: [{ type: 'bar', data: [5, 12, 9] }] });
chart.resize();

#4) Open a View (Drawer)

const popupUid = ctx.model.uid + '-1';
await ctx.openView(popupUid, { mode: 'drawer', title: ctx.t('Sample drawer'), size: 'large' });

#5) Read a Resource and Render JSON

const resource = ctx.createResource('SingleRecordResource');
resource.setDataSourceKey('main');
resource.setResourceName('users');
await resource.refresh();
ctx.render(`<pre style="padding:12px;background:#f5f5f5;border-radius:6px;">${JSON.stringify(resource.getData(), null, 2)}</pre>`);

#Notes

  • It is recommended to use trusted CDNs for loading external libraries.
  • Selector Usage Advice: Prioritize using class or [name=...] attribute selectors. Avoid using fixed ids to prevent conflicts from duplicate ids when using multiple blocks or popups.
  • Event Cleanup: Since the block may re-render multiple times, event listeners should be cleaned up or deduplicated before binding to avoid repeated triggers. You can use a "remove then add" approach, a one-time listener, or a flag to prevent duplicates.

#Related Documents

  • Variables and Context
  • Linkage Rules
  • Views and Popups