Skip to main content
This page documents all React components used in the HubSpot Form Builder application, including their props, types, and usage.

App Component

The root application component that orchestrates the entire form builder interface. Location: main/frontend/src/App.tsx

State Management

The App component manages the following state:
viewMode
'edit' | 'preview'
Current view mode of the application
zoomLevel
number
default:"100"
Zoom level for the edit view (50-200)
selectedFormId
string
Currently selected HubSpot form ID
generatedModule
Blob | null
Generated HubL module blob ready for download
isGenerating
boolean
Whether module generation is in progress

Key Features

  • Integrates drag-and-drop functionality via @dnd-kit
  • Manages zoom controls for canvas
  • Handles module generation and download
  • Coordinates between edit and preview modes

Usage Example

import App from './App';

// Rendered as root component
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);

The left panel containing connection status, form selector, layout options, and field palette. Location: main/frontend/src/components/Sidebar.tsx

Props

connected
boolean
required
Whether HubSpot OAuth connection is active
onRefresh
() => void
required
Callback to refresh connection status
forms
HubSpotForm[]
required
Array of available HubSpot forms
loading
boolean
required
Whether forms are currently loading
error
string | null
required
Error message if form loading failed
selectedFormId
string
required
Currently selected form ID
onSelectFormId
(formId: string) => void
required
Callback when a form is selected
schema
FormSchema | null
required
Form schema containing field definitions
schemaLoading
boolean
required
Whether schema is currently loading
schemaError
string | null
required
Error message if schema loading failed

HubSpotForm Type

type HubSpotForm = {
  id: string;
  name: string;
  createdAt: number;
  updatedAt: number;
};

Sections

The Sidebar contains four main sections:
  1. Connection - HubSpotConnect component
  2. Select Form - FormSelector component
  3. Layout Options - Mode selector and step management
  4. Detected Fields - Draggable field palette

Usage Example

<Sidebar
  connected={connected}
  onRefresh={checkStatus}
  forms={forms}
  loading={loading}
  error={error}
  selectedFormId={selectedFormId}
  onSelectFormId={setSelectedFormId}
  schema={schema}
  schemaLoading={schemaLoading}
  schemaError={schemaError}
/>

LayoutBuilder

The canvas component that displays the form layout with draggable fields and steps. Location: main/frontend/src/components/LayoutBuilder.tsx

Props

schema
FormSchema | null
required
Form schema containing field definitions
dropPositions
Map<string, 'before' | 'after' | 'inside' | null>
required
Visual indicators for drop positions during drag operations

Features

  • Renders sortable steps using @dnd-kit/sortable
  • Each step contains rows of fields
  • Fields can be dragged within and between rows
  • Steps can be renamed and deleted (minimum 1 step required)
  • Required fields cannot be deleted

Child Components

SortableStep

Internal component for rendering individual steps. Props:
step
Step
Step data containing id, title, and rows
fields
FieldSchema[]
All available fields from the form schema
onRename
(stepId: string, title: string) => void
Callback to rename a step
onDelete
() => void
Callback to delete the step
onDeleteField
(fieldName: string) => void
Callback to remove a field from the step
canDelete
boolean
Whether the step can be deleted
dropPositions
Map<string, 'before' | 'after' | 'inside' | null>
Drop position indicators

FieldItem

Internal component for rendering individual fields. Props:
fieldId
string
Unique field identifier
fieldLabel
string
Display label for the field
required
boolean
Whether the field is required
position
'before' | 'after' | 'inside' | null
Current drop position indicator
onDelete
() => void
Callback to delete the field

Usage Example

<LayoutBuilder 
  schema={schema} 
  dropPositions={dnd.dropPositions} 
/>

PreviewPanel

Interactive form preview with validation and multi-step navigation. Location: main/frontend/src/components/PreviewPanel.tsx

Props

schema
FormSchema | null
required
Form schema containing field definitions
layout
LayoutState | null
required
Current layout configuration

Features

  • Renders form using Shadow DOM for style isolation
  • Full form validation (required fields, email, phone)
  • Multi-step navigation with progress indicators
  • Simulated form submission
  • Responsive field rendering

Field Types Supported

  • text - Single-line text input
  • email - Email input with validation
  • phone - Phone number input with validation
  • number - Numeric input
  • textarea - Multi-line text input
  • select / dropdown - Dropdown selection
  • radio - Radio button group
  • checkbox - Single checkbox
  • multiple_checkboxes - Multiple checkbox group

Validation Rules

required
boolean
Field must have a non-empty value
email
pattern
Must match email regex: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
phone
pattern
Must match phone regex for international formats

State Management

currentStep
number
Index of currently displayed step
formData
Record<string, string>
User-entered form values
formErrors
Record<string, string>
Validation error messages by field name
isSubmitted
boolean
Whether form has been successfully submitted

Usage Example

<PreviewPanel 
  schema={schema} 
  layout={layout} 
/>

FormSelector

Dropdown for selecting a HubSpot form with schema preview. Location: main/frontend/src/components/FormSelector.tsx

Props

connected
boolean
required
Whether HubSpot OAuth connection is active
forms
HubSpotForm[]
required
Available forms to select from
loading
boolean
required
Loading state for forms list
error
string | null
required
Error message if any
selectedFormId
string
required
Currently selected form ID
onSelectFormId
(formId: string) => void
required
Callback when selection changes
schema
FormSchema | null
required
Schema of selected form
schemaLoading
boolean
required
Loading state for schema
schemaError
string | null
required
Schema loading error

Features

  • Displays forms in a dropdown
  • Shows field types for selected form
  • Handles session expiration with reconnect prompt
  • Empty state when no forms available

Usage Example

<FormSelector
  connected={connected}
  forms={forms}
  loading={loading}
  error={error}
  selectedFormId={selectedFormId}
  onSelectFormId={onSelectFormId}
  schema={schema}
  schemaLoading={schemaLoading}
  schemaError={schemaError}
/>

HubSpotConnect

OAuth connection status and control component. Location: main/frontend/src/components/HubSpotConnect.tsx

Props

connected
boolean
required
Current connection status
onRefresh
() => void
required
Callback to refresh connection status

Features

  • Connected State: Shows status badge, refresh button, and logout button
  • Disconnected State: Shows connect button that redirects to OAuth flow
  • Confirms before logout
  • Reloads page after successful logout

API Endpoints Used

API_ENDPOINTS.oauthInstall
string
Redirects to HubSpot OAuth authorization
API_ENDPOINTS.oauthLogout
POST
Clears OAuth session

Usage Example

<HubSpotConnect 
  connected={connected} 
  onRefresh={checkStatus} 
/>

DetectedFieldItem

Internal component for draggable field items in the sidebar palette. Location: main/frontend/src/components/Sidebar.tsx

Props

field
FieldSchema
required
Field schema containing name, label, type, and required flag

Features

  • Uses useDraggable from @dnd-kit/core
  • Visual feedback during drag
  • Shows required badge for required fields
  • ID format: palette:{fieldName}

Usage Example

{availableFields.map((field) => (
  <DetectedFieldItem key={field.name} field={field} />
))}

Type Definitions

FormSchema

type FormSchema = {
  id: string;
  name: string;
  fields: FieldSchema[];
};

FieldSchema

type FieldSchema = {
  name: string;
  label: string;
  type: string;
  required: boolean;
  options?: FieldOption[];
  validation?: Record<string, unknown>;
};

FieldOption

type FieldOption = {
  label: string;
  value: string;
};

LayoutState

type LayoutState = {
  mode: 'one-step' | 'multi-step';
  steps: Step[];
};

Step

type Step = {
  id: string;
  title: string;
  rows: Row[];
};

Row

type Row = {
  id: string;
  fields: string[]; // Array of field names (max 3 per row)
};

Build docs developers (and LLMs) love