Login Page Builder

No-code drag-and-drop visual canvas with 3 design modes (Freeform, Grid, Builder), 14 component types, a 12-column responsive grid system, real-time preview sync, and JSON serialization.

The Login Page Builder is SCRIPE's most advanced customization tool — a fully visual, drag-and-drop canvas that allows tenant administrators to build custom login page layouts without writing any code. The builder provides 3 design modes (Freeform, Grid, and Builder), a palette of 14 pre-built component types (from logos and headings to social login buttons and footer links), a responsive 12-column CSS grid system, real-time two-way sync with the preview iframe, and full JSON serialization for persistence. The builder integrates seamlessly with the Login Customizer Studio's design token pipeline, ensuring that builder-created layouts inherit all theme colors, typography, and accessibility settings.

3 Canvas Modes

The builder offers three distinct canvas modes, each providing a different level of control over layout positioning. Users can switch between modes at any time — components are preserved during mode switches.

Freeform Mode

Absolute positioning with pixel-level control. Components can be placed anywhere on the canvas and dragged to exact coordinates. Best for creative, non-standard layouts where design freedom is paramount. Components have x/y position, width, height, and z-index properties.

Grid Mode (12-Column)

Responsive 12-column CSS grid layout. Components are placed into grid cells with configurable column span (1–12), row positioning, alignment, and gap spacing. The grid ensures consistent, responsive layouts that adapt to desktop, tablet, and mobile breakpoints. This is the recommended mode for enterprise deployments where cross-device consistency is critical.

Builder Mode

Structured block-based layout with predefined sections. Components are organized into vertical sections (header, body, footer) with automatic stacking and reordering via drag-and-drop. Best for quick layout assembly with predictable, clean results. Builder mode enforces structural constraints — components snap to section boundaries and maintain consistent spacing.

ModePositioningGridBest For
FreeformAbsolute (x, y)NonePixel-perfect creative layouts
GridRow / Column based12-column CSS gridResponsive enterprise layouts
BuilderSection-basedAuto-spaced blocksQuick structured assembly

14 Component Types

The component palette provides 14 pre-built, configurable UI components that can be dragged onto the canvas. Each component has a set of editable properties (text content, styling, behavior) accessible via the Properties Panel when selected.

ComponentTypeGrid SpanKey Properties
Logologo2-4src, width, height, alignment
Headingheading4-12text, level (h1-h6), color, weight
Body Texttext4-12content, fontSize, lineHeight
Login Formform4-8fields, submitLabel, forgotLink
Social Loginsocial4-8providers[], layout, separator
Imageimage2-12src, alt, objectFit, borderRadius
Buttonbutton2-6label, variant, icon, href
Cardcard4-12children[], padding, shadow
Dividerdivider4-12style (line/dotted/gradient)
Spacerspacer12height (px)
Badgebadge2-4text, variant, icon
Iconicon1-2name, size, color
Footerfooter12links[], copyright, alignment
Terms Linkterms4-8tosUrl, privacyUrl, text

Logo — Displays the tenant's logo image. Properties: src (URL), alt text, width, height, alignment, link URL. Supports SVG, PNG, and WebP formats.

Heading — Large display text for page titles and headlines. Properties: text content, font size, font weight, color, alignment, HTML tag (h1–h6). Supports dynamic variables ({tenantName}).

Form — The login form component containing email/password inputs and submit button. Properties: show labels, show placeholders, input style, button text, remember me checkbox, forgot password link.

Social Login — Pre-built social authentication buttons (Google, Microsoft, Apple, GitHub). Properties: providers (multi-select), layout (horizontal, vertical, icon-only), separator text.

12-Column Grid System

The Grid Mode uses a responsive 12-column CSS grid layout. Each component occupies a configurable number of columns (1–12) and rows. The grid supports gap spacing, column alignment (start, center, end, stretch), and row alignment. The grid is fully responsive — column spans can be configured independently for desktop (lg), tablet (md), and mobile (sm) breakpoints.

Grid Component Properties

Each component in Grid mode has additional grid-specific properties: colSpan (1–12 columns), rowSpan (number of rows), colStart (starting column), rowStart (starting row), alignment (start/center/end/stretch), and responsive overrides (sm/md/lg column spans). These properties are configured via the Properties Panel.

Grid System ImplementationCSS
.builder-canvas-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--builder-gap, 16px);
  padding: var(--builder-padding, 24px);
}

.grid-item[data-span="4"]  { grid-column: span 4; }
.grid-item[data-span="6"]  { grid-column: span 6; }
.grid-item[data-span="12"] { grid-column: span 12; }

@media (max-width: 768px) {
  .builder-canvas-grid { grid-template-columns: repeat(4, 1fr); }
  .grid-item { grid-column: span 4 !important; }
}

@media (max-width: 480px) {
  .builder-canvas-grid { grid-template-columns: 1fr; }
}

Responsive Breakpoints

The grid supports 3 breakpoints: Desktop (lg, ≥1024px), Tablet (md, 768–1023px), and Mobile (sm, <768px). Each component can have independent column spans per breakpoint. For example, a logo might span 4 columns on desktop but 12 columns (full width) on mobile. The preview iframe respects these breakpoints when device toggles are used.

BreakpointScreenColumnsBehavior
Desktop (lg)≥ 1024px12Full grid — all spans honored
Tablet (md)768-1023px4Components collapse to 4-column spans
Mobile (sm)< 480px1Single column — all components full-width

Gap Configuration

The grid gap (spacing between cells) is configurable globally: columnGap and rowGap properties, each accepting pixel values (default: 16px). This ensures consistent spacing across all grid items without manual padding on individual components.

Drag-and-Drop Architecture

The builder uses @dnd-kit/core (not react-beautiful-dnd) for drag-and-drop interactions. Components are dragged from the palette sidebar and dropped onto the canvas. The DragOverlay renders a ghost preview of the component during drag. Drop zones are highlighted with blue outlines when a draggable component hovers over them.

Palette → Canvas Flow

1. User drags a component type from the palette sidebar. 2. @dnd-kit creates a DragOverlay with a preview of the component. 3. The canvas renders drop zone indicators (grid cells in Grid mode, free areas in Freeform mode). 4. On drop, a new component instance is created with default properties and added to the builder state. 5. The component is rendered on the canvas at the drop position.

Drag & Drop Component Lifecycle
Component Palette (14 types)
Drag Start (@dnd-kit/core)
Canvas Drop Zone (collision detection)
Create Component (defaults + auto-ID)
Select Component (Properties Panel)

Canvas Reordering

Existing components on the canvas can be reordered by dragging. In Grid mode, components snap to grid cells. In Builder mode, components reorder within their section (header/body/footer). In Freeform mode, components move to the exact drop coordinates.

Component Selection

Clicking a component on the canvas selects it, displaying a blue selection border and resize handles. The Properties Panel on the right sidebar loads the selected component's editable properties. Pressing Delete/Backspace removes the selected component. Escape deselects.

Properties Panel

The Properties Panel is a contextual sidebar that appears when a component is selected on the canvas. It displays all editable properties for the selected component type, organized into sections: Content (text, URLs), Layout (width, height, alignment), Style (colors, borders, shadows), and Grid (column span, row span, responsive breakpoints). Changes in the Properties Panel update the canvas in real-time.

Content Properties

Text inputs for content: headline text, paragraph text, button labels, URLs, alt text. Supports variable interpolation with {variableName} syntax for dynamic tenant data.

Style Properties

Visual styling controls: color pickers, border radius sliders, shadow toggles, opacity controls, font size selectors. Style properties that overlap with theme tokens (e.g., primaryColor) can be set to 'inherit from theme' to maintain consistency.

Grid Properties

Grid-specific layout controls (Grid mode only): column span slider (1–12), row span, column start, row start, alignment select, and responsive breakpoint overrides. A visual grid preview shows the component's position within the 12-column grid.

Property TypeUI ControlExample
textInput fieldHeading text, button label
numberSlider / number inputWidth, height, padding
colorColor pickerText color, background
selectDropdownText alignment, font weight
booleanToggle switchShow shadow, center align
imageFile picker / URLLogo src, background image
arrayList editorSocial providers, footer links

Canvas State Management

The builder maintains a flat array of BuilderComponent objects in the StudioDraft. Each component has: id (unique UUID), type (one of 14 types), properties (key-value map), position (x, y for Freeform), gridPosition (col, row, colSpan, rowSpan for Grid), and section (header/body/footer for Builder mode). The entire array is serialized as JSON in the builderComponentsJson field of DraftBrandingJson.

BuilderComponent Schema

Each BuilderComponent is a serializable object: { id: string, type: ComponentType, props: Record<string, unknown>, position: { x: number, y: number }, gridPosition: { colSpan: number, rowSpan: number, colStart: number, rowStart: number }, section: 'header' | 'body' | 'footer', order: number, responsive: { sm: GridOverride, md: GridOverride } }.

Builder Component State SchemaTypeScript
export interface CanvasComponent {
  id: string;                      // Unique identifier (UUID v4)
  type: CanvasComponentType;       // Component type selector
  gridColumn: string;              // CSS Grid Column (e.g. "1 / 7")
  gridRow: string;                 // CSS Grid Row (e.g. "1 / 2")
  alignment: GridAlignment;        // Horizontal alignment (start/center/end)
  verticalAlignment: GridAlignment;// Vertical alignment (start/center/end)
  x: number;                       // Absolute mode X coordinate (px)
  y: number;                       // Absolute mode Y coordinate (px)
  width: number;                   // Absolute mode width (px)
  height: number;                  // Absolute mode height (px)
  locked: boolean;                 // Lock element from modifications
  props: Record<string, unknown>;  // Element specific settings (e.g. src, text)
  zIndex: number;                  // Absolute mode stacking z-index
  visible: boolean;                // Visibility switch
}

Undo/Redo Support

The builder maintains a history stack for undo/redo operations. Each action (add, move, resize, delete, property change) pushes a snapshot to the stack. Ctrl+Z undoes the last action, Ctrl+Shift+Z redoes. The history stack has a configurable depth limit (default: 50 actions).

Builder State Save & Sync Pipeline
Canvas Interaction (Move / Resize Component)
Coordinates Snapped to Grid (8px grid spacing, adjusted by zoom)
Zustand Store Updates components array state
Interaction Committed -> History Stack (Max 50)
postMessage Broadcasts components schema to Preview Iframe
Debounced (2s) Save to Server (PUT /api/v1/branding/draft)
Publish Action -> Promotes DraftBrandingJson to LiveBrandingJson

JSON Serialization & Persistence

The builder state is serialized as a JSON array and stored in the builderComponentsJson field of the tenant's DraftBrandingJson. The canvasMode (freeform/grid/builder) is stored as a separate field. On publish, the builder state is promoted to LiveBrandingJson alongside all other branding tokens.

Serialized Schema

The stored JSON follows this structure: { canvasMode: 'freeform' | 'grid' | 'builder', gridConfig: { columns: 12, columnGap: 16, rowGap: 16 }, components: [ { id, type, props, position, gridPosition, section, order, responsive } ] }. The schema is versioned for forward compatibility.

Builder Canvas JSONJSON
{
  "canvasMode": "grid",
  "gridConfig": { "columns": 12, "columnGap": 16, "rowGap": 16 },
  "components": [
    {
      "id": "comp-1",
      "type": "logo",
      "props": { "width": 120, "alignment": "center" },
      "gridPosition": { "colSpan": 4, "colStart": 4, "rowStart": 0 }
    },
    {
      "id": "comp-2",
      "type": "heading",
      "props": { "text": "Welcome", "level": "h1" },
      "gridPosition": { "colSpan": 8, "colStart": 2, "rowStart": 1 }
    }
  ]
}

Storage Optimization

Default property values are NOT stored — only properties that differ from the component type's defaults are serialized. This keeps the JSON payload compact (typically 2–5KB for a complex layout with 10+ components).

Real-Time Preview Sync

Every canvas change is immediately reflected in the sandboxed preview iframe. The builder emits postMessage events containing the current component array and canvas mode. The preview page receives these events, reconstructs the layout, and renders the components with live CSS variable injection from the active theme.

Two-Way Sync

The sync is bidirectional: canvas changes propagate to preview (via postMessage), and device toggle changes in the preview header propagate back to the builder (updating responsive breakpoint indicators). This ensures the builder canvas accurately reflects how the layout will appear at each breakpoint.

Security Constraints

The Login Page Builder enforces strict security constraints on user-generated content. All text content is HTML-sanitized before rendering (no script injection). Image URLs are validated to prevent SSRF. The builder canvas runs in a sandboxed iframe with restrictive CSP headers. Custom CSS injection is not supported — styling is controlled exclusively through the design token pipeline.

Input Sanitization

All text properties (headings, paragraphs, button labels) are sanitized using DOMPurify before rendering in the preview. HTML tags are stripped — only plain text is stored. URLs are validated against a whitelist of allowed protocols (https, http) to prevent javascript: and data: injection.

Iframe Sandboxing

The preview iframe uses the sandbox attribute with restricted permissions: allow-scripts (for CSS variable injection), allow-same-origin (for postMessage). Forms are non-functional — the preview renders visual-only representations of auth components.

ThreatMitigation
XSS via text propsDOMPurify sanitization — all HTML stripped, plain text only
Script injection in URLsProtocol whitelist: https://, http://, / only. Block javascript:, data:
Oversized canvasMax 50 components per canvas. Max 10KB serialized JSON
Cross-tenant accessCanvas state in TenantSettings.DraftBrandingJson — tenant-scoped
Concurrent editsOptimistic concurrency (SettingsVersion). 409 Conflict on stale write

Dashboard Theming (Related Feature)

The Dashboard Theming panel in the Customizer Studio allows tenants to configure their admin dashboard's visual defaults. Settings include layout template (8 options), color theme (12 options), theme mode (light/dark/system), default language, and sidebar default state. Dashboard theming uses the same draft/publish workflow as login branding.

8 Layout Templates

Default, Navigation, Classic, Compact, Elegant, Floating, Modern, and Minimal. Each template defines the dashboard shell structure: sidebar position, header style, content width, and navigation pattern.

12 Color Themes

Default, Zinc, Slate, Stone, Neutral, Red, Rose, Orange, Green, Blue, Violet, and Yellow. Each color theme defines the dashboard's accent color palette applied to the sidebar, headers, buttons, and active states.

Storage Format

Dashboard settings are stored in the dashboardThemeJson field of DraftBrandingJson as a JSON object: { layoutTemplate, colorTheme, mode, language, sidebarDefaultState }. On publish, the settings are promoted to the tenant's live configuration.

SettingOptionsStorage
Layout Template8 templatesdashboardThemeJson.layoutTemplate
Color Theme12 palettesdashboardThemeJson.colorTheme
Theme ModeLight / Dark / SystemdashboardThemeJson.theme
LanguageEN / AR (RTL auto)dashboardThemeJson.language
SidebarExpanded / CollapseddashboardThemeJson.sidebarCollapsed

Bundle Marketplace (Related Feature)

The Bundle Marketplace allows tenants to save their complete studio configuration (login theme + builder layout + dashboard settings + per-page overrides) as a named bundle, and browse/apply bundles created by other tenants or the system. Bundles are displayed in a dedicated tab within the Theme Gallery.

Bundle Components

BundleGalleryTab (5.6KB) — Gallery tab with type filters (Login, Dashboard, Complete), search, grid, pagination. BundleCard (12.8KB) — Card with accent preview, pricing tier, metadata. BundleDetailModal (8.5KB) — Full detail with apply button. SaveBundleDialog (7.6KB) — Dialog for saving current studio state as a new bundle.

Bundle Types

Login Bundle — Contains only login branding (theme tokens + builder layout). Dashboard Bundle — Contains only dashboard settings. Complete Bundle — Contains everything: login branding, builder layout, per-page overrides, dashboard settings, and accessibility configuration. Complete bundles provide one-click full-workspace setup.

Bundle TypeIncludesUse Case
LoginLogin theme + builder canvas + per-page overridesAuth-only branding
DashboardDashboard layout + color theme + modeAdmin panel theming
CompleteEverything: login + builder + dashboard + accessibilityFull platform rebrand

Module Architecture

The Login Page Builder follows SCRIPE's standard modular clean architecture. The builder/ directory contains: BuilderCanvas.tsx (main canvas), ComponentPalette.tsx (sidebar palette), PropertiesPanel.tsx (property editor), GridOverlay.tsx (grid visualization), and BuilderToolbar.tsx (mode switcher, undo/redo, zoom controls). State management uses the useBuilderState hook integrated into useStudioViewModel.

Login Page Builder ComponentsText
src/modules/customization/branding/src/presentation/
├── components/
│   ├── builder/
│   │   ├── BuilderCanvas.tsx          # Main canvas — absolute/grid positioning
│   │   ├── BuilderPanel.tsx           # Side palette controller
│   │   ├── GridOverlay.tsx            # CSS Grid layout helper lines
│   │   └── DraggableCanvasItem.tsx    # Draggable item wrapper
│   └── views/
│       └── CustomizerStudioView.tsx   # Customizer workspace frame
├── hooks/
│   └── useBuilderDnd.ts               # @dnd-kit/core sensor integrations
└── viewmodels/
    ├── useBuilderStore.ts             # Zustand state manager & snap calculation
    └── useStudioViewModel.ts          # Studio logic bridge & debounced HTTP saves