How No‑Code Platforms Transform Frontend Development: Architecture, Canvas & Drag‑Drop Techniques

This article explores the rise of no‑code/low‑code builder platforms, detailing their core concepts, architecture, UIDL specifications, sandboxing, drag‑and‑drop mechanics, smart snapping, component insertion, and event handling, offering practical insights for frontend engineers building modern visual editors.

ELab Team
ELab Team
ELab Team
How No‑Code Platforms Transform Frontend Development: Architecture, Canvas & Drag‑Drop Techniques

What Is a Builder Platform?

Before introducing builder platforms, the unavoidable theme is NCLC (No Code & Low Code). NCLC, as the core concept behind site‑building products, has driven successive waves of technology.

Recent years have seen various products around NCLC, such as project management Meego, low‑code system Retool, online document Notion, and even a division into 12 development tracks.

No‑code low‑code ecosystem diagram
No‑code low‑code ecosystem diagram

The most rapidly growing and representative product form in the industry is the site‑building category. Classic examples include early Dreamweaver, the billion‑dollar SaaS Webflow, and various domestic builder platforms.

Builder platforms are popular because they solve two major enterprise pain points: development efficiency and staff transformation.

Development efficiency: Builder platforms, like IDEs, aim to boost productivity, but they focus on "reuse and composition" rather than raw business logic. Drag‑and‑drop components replace traditional coding.

For example, creating a poster‑style activity page with many images and animations would take days with code, but with a builder platform it can be done by dragging and configuring assets once.

In short, builder platforms provide a new development paradigm that hides complexity for specific scenarios such as e‑commerce activities, marketing promotions, and back‑office tools.

Staff transformation: In the fast‑changing market, digital transformation is widely accepted, and NCLC enables employees without programming experience to build applications.

Among builder platform users, non‑technical operations staff are the most common; they can generate required pages without developer involvement, reducing resource waste and improving workflow efficiency.

Derived Concepts

During development, builder platforms have spawned many concepts. The core can be summarized as:

Builder platform = Editor (canvas + configurator) + Generator, with assets as materials and UIDL as the communication protocol.

The editor and generator are decoupled via UIDL, so page types depend only on the used materials.

Editor renders front‑end material and produces UIDL.

Generator consumes UIDL and, based on predefined templates, produces the final page.

This layered design separates responsibilities, allowing each layer to evolve independently.

Architecture Design

IOC Architecture

Modules are coupled through an IOC architecture: each module defines its usage contract, and the container injects dependencies at runtime. This makes modules independent of concrete implementations and facilitates independent iteration and extensibility.

For example, different terminals (TV, mobile) share the same canvas functionality but differ in resolution and focus handling; IOC allows these differences to be added as extensions.

Overall, IOC provides a plugin‑friendly, extensible design.

Editor‑Renderer Layer Separation

The canvas is split into a rendering layer and an editing layer, communicating via a protocol to stay decoupled.

Editor and render layer separation diagram
Editor and render layer separation diagram

Users interact with the editing layer; interactions are reflected on the rendering layer.

When a component is selected, eight anchor points appear on the rendering layer.

Page preview can be achieved by removing the editor’s mask for instant preview.

Interaction experience improves because anchor points exist only on the rendering layer.

The design cleanly separates editing specifications from rendering specifications.

interface ComponentAddAction {}
interface ComponentDragAction {}
...
interface ComponentFocusRenderer {}
interface ComponentMirrorRenderer {}
...

Some implementations use an iframe to separate rendering and editing, providing sandboxing and easier multi‑user collaboration.

Iframe offers natural sandboxing, preventing style and logic leakage.

Multi‑user editing can switch from iframe communication to WebSocket.

Event System

The platform builds a comprehensive event system, where each functional module can consume events corresponding to editing actions, rendering actions, or global actions.

Typical events include:

Init event on page load triggers side‑bar material loading, canvas rendering, and dependency loading.

dragEnd event on component drop triggers material loading, configurator parsing, and canvas cleanup.

Event system diagram
Event system diagram

Specification Design

Design around concrete scenarios; avoid blind feature stacking.

Specification first: standards drive the editor.

Two key specifications are covered next: UIDL and Material specifications.

UIDL Specification

UIDL: Describes all UI‑related structured information when building a page.

Originally proposed by teleporthq, UIDL is a JSON‑based universal format that enables:

Generating the same UI with various tools and frameworks.

Seamless transition between code outputs.

Advanced programmatic manipulation.

interface ComponentProps { id: string; [key: string]: any; }
interface Schema { id: string; type: MaterialId; name: string; children: Schema[]; props: ComponentProp; }
interface UIDL { meta: { version: string }; project: { id: string; title: string; version: string; author: User; url: string }; schema: Schema; materials: { components: Array<Component> }; }

Material Specification

Material: Describes the components, plugins, and actions needed to enrich a page.

Materials are classified by:

Terminal: mobile web, mini‑program, TV, etc.

Form: component, plugin, action.

Function: basic component, container component, interactive component, etc.

External attributes (terminal, business line) and internal attributes (form, function) together define a material.

Canvas Design

This part dives into the canvas’s core challenges and implementation approaches.

Example case: a user named "Xiaoshuai" needs to create a promotional page. He drags an image, text, and button component onto the canvas, configures them, and publishes the page.

Promotional page example
Promotional page example

The key workflow is: add component → drag component → select component → configure component (configurator) → publish (generator).

Add Component

Two core steps:

Load the component’s material into the platform.

Generate a Schema node for the component and insert it into UIDL after drag ends.

Schema Generation

Pseudo‑code for generating a Schema node:

genSchema(component: ComponentMaterial): Schema {
  const children: Schema[] = [];
  const props = {};
  const styles: React.CSSProperties = SchemaService.defaultStyles;
  return {
    id: this.genComponentId(),
    type: component.id,
    name: component.name,
    props,
    children,
    styles
  };
}

Load Material

Materials are loaded on demand to keep the builder responsive. The loading strategy must align with the bundling format.

Packaging Specification

Four common module formats are discussed: AMD, CJS, UMD, ESM. Modern front‑end trends favor ESM for its standardization and tooling support.

AMD

CJS

ESM

Advantages

1. Asynchronous loading, suitable for modular scenarios.

2. Good compatibility with RequireJS.

Advantages

Synchronous loading, intuitive syntax.

Advantages

1. Supports both sync and async loading.

2. Optimized for front‑end bundling.

3. Standardized, future‑proof.

Disadvantages

1. Syntax not intuitive.

2. Requires runtime conventions.

3. Limited bundling optimization.

4. Not standardized.

Disadvantages

1. Not browser‑compatible.

2. Isolated spec.

3. Not standardized.

Disadvantages

Compatibility issues in CJS projects; many libraries need conversion.

Scenario

Browser

Scenario

Node

Scenario

Browser & Node

Material Loading Solutions

Two main solutions are compared:

Solution

Advantages

Disadvantages

systemJS

1. Supports AMD/ESM/CJS.

2. Actively maintained with bundler support.

No context concept leads to compatibility gaps.

RequireJS

1. Supports AMD and CJS.

2. Good spec compatibility.

Syntax not intuitive; requires promisify.

Overall, systemJS is recommended for modern bundlers and complex dependency handling.

Dependency Analysis

Materials may depend on:

Base frameworks/libraries : React, React‑DOM, etc.

Frameworks specific to a component : e.g., xg‑player.

Other components : button list depends on button component.

To avoid redundancy, dependencies are handled differently:

Base frameworks are treated as shared and not bundled with each material.

Component‑specific frameworks are bundled with the material.

Component dependencies are declared so that dependent materials load first.

Sandboxing

Each material runs as an isolated executable unit within the same runtime. Isolation can be logical (Eval, Function, Proxy) or style‑based (CSS modules, Shadow DOM).

Logical Isolation

const varBox = {};
const fakeWindow = new Proxy(window, {
  get(target, key) { return varBox[key] || window[key]; },
  set(target, key, value) { varBox[key] = value; return true; }
});
const fn = new Function('window', code);
fn(fakeWindow);

Style Isolation

Options include CSS‑modules, styled‑components, or wrapping the component in a Shadow DOM.

let elementRef = document.querySelect('#sub-app');
let shadow = elementRef.attachShadow({mode: 'open'});

Drag Component

Drag‑and‑drop is a core difficulty. The platform must capture start, move, and end events, providing data such as direction, distance, position, and boundary scrolling.

Using MouseDown/MouseMove/MouseUp instead of native drag events gives finer control over position and direction.

Drag Library

Libraries abstract event listening and data collection. Typical phases:

Start – MouseDown, distance threshold, start callback.

Move – MouseMove/Scroll, non‑fixed layout handling, direction, distance, position, move callback, auto‑scroll, cursor change.

End – MouseUp, final position, end callback.

Mirror Component

A mirror component is rendered during drag to provide immediate visual feedback and preload resources.

let componentMap = {};
let mirror = { move: xxx, destroy: xxx };

onMouseDown = (e) => {
  const schema = genSchema(e);
  const schema = loadComponent(schema);
  mirror = renderMirror(schema);
};

onMouseMove = (e) => { mirror.move(e); };

onMouseUp = (e) => { mirror.destroy(); };

loadComponent = (schema) => {
  if (componentMap[schema.type]) return;
  componentMap[schema.type] = systemjs.loadModule(schema.url);
};

renderMirror = (schema) => {
  const mirrorEl = document.createElement('div');
  document.body.appendChild(mirrorEl);
  const Mirror = componentMap[schema.type];
  ReactDOM.render(<Mirror />, mirrorEl);
};

Component Anchors

Component anchors are indispensable in drag‑and‑drop.

Eight anchors appear around a selected component, enabling resizing and alignment.

Component anchor points diagram
Component anchor points diagram

Smart Snapping

Smart snapping improves placement accuracy. Three types are covered:

Position Snapping

If a component’s position is within a small threshold (1‑5 px) of another component’s edge, it automatically aligns.

Position snapping reference lines
Position snapping reference lines

Distance Snapping

The platform detects consistent margins between components and aligns new components to match existing spacing.

Distance snapping illustration
Distance snapping illustration

Size Snapping

When resizing, if the new width or height matches another component within a tolerance, the size snaps to that value.

Size snapping illustration
Size snapping illustration

Component Insertion

When inserting a component, its Schema node is added to UIDL, and the canvas re‑renders based on the updated UIDL.

type Props = { id: ComponentId; key?: string };
const DynamicComponent: React.FC<Props> = ({ id }) => {
  const [schema, version] = useSchema(id);
  const moduleMap = useSelector(state => state.material.moduleMap);
  const { children = [], type, props, name } = schema;
  const Module = moduleMap[type];
  return (
    <Module key={id} {...props}>
      {children.map(child => (
        <DynamicComponent key={child.id} id={child.id} />
      ))}
    </Module>
  );
};

Select Component

Event Dispatch

After a component is selected, an event system propagates the interaction. Two approaches exist: per‑component event binding or a global listener that resolves the target element. The article recommends per‑component binding for simplicity.

Using display:contents can create a ghost node that forwards events without affecting layout.

function withEventProvider<P>(Component: React.ComponentType<P>): React.ComponentType<P> {
  const Wrapped: React.ComponentType<P> = (props) => (
    <div style={{ display: 'contents' }} onClick={e => console.log(e, props)}>
      <Component {...props} />
    </div>
  );
  const name = Component.displayName ?? Component.name ?? 'Unknown';
  Wrapped.displayName = `withEventProvider(${name})`;
  return Wrapped;
}

Quick Operations

Delete Component : Remove the component’s Schema node and re‑render.

Copy & Paste : Store a copied Schema in a temporary variable; on paste, insert a new node with adjusted left and top to avoid overlap.

Cut Component : Combine copy‑paste with deletion.

Text Editing : Components declare data-edit="propKey"; the editor makes those nodes contentEditable and syncs changes back to the Schema.

Component Rotation : Compute angle difference between mouse‑down and mouse‑move vectors relative to the component’s center.

Multiple Component Selection

Selection Area

When dragging the mouse, a translucent rectangle shows the selection region. The final selection is the minimal bounding rectangle covering all fully contained components.

let startPoint = null;
const area = { width: 0, height: 0, x: 0, y: 0 };
const onMouseDown = e => { startPoint = new Point(e); registerMoveAndUp(); };
const onMouseMove = e => {
  area.width = Math.abs(e.x - startPoint.x);
  area.height = Math.abs(e.y - startPoint.y);
  area.x = Math.min(e.x, startPoint.x);
  area.y = Math.min(e.y, startPoint.y);
};

Batch Operations

After selecting multiple components, users can move or resize them together. The platform may create a temporary outer container for the group, move it, and then apply the delta to each component’s Schema.

Conclusion

The article has dissected the core entity of a builder platform—the canvas—covering architecture, UIDL, sandboxing, drag‑and‑drop, smart snapping, component insertion, event dispatch, quick operations, and multi‑selection.

Future articles will address the configurator and generator modules.

Canvaslow-codeFrontend Architectureno-codeDrag and DropUIDLcomponent sandboxing
ELab Team
Written by

ELab Team

Sharing fresh technical insights

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.