A comprehensive React-based survey builder and renderer ecosystem featuring a powerful visual drag-and-drop interface for creating dynamic, interactive surveys and forms with advanced conditional logic, multiple layout options, and extensive customization capabilities.
- Drag-and-Drop Interface: Intuitive visual editor with real-time preview
- 18+ Unified Block Types: Text inputs, radio buttons, checkboxes, file uploads, matrices, date pickers, and more
- Unified Block System: Single-file block definitions combining builder and renderer components
- Custom Block Support: Easily extend with your own unified block definitions using
registerBlock() - Node-Based Architecture: Hierarchical survey structure with sections and pages
- Live Preview: See your survey as you build it
- Conditional Logic: Show/hide blocks based on user responses with complex condition rules
- Navigation Rules: Custom routing between survey sections based on user input
- Calculated Fields: Dynamic field calculations and computed values
- Branching Logic: Smart survey flow with condition-based page navigation
- BMI Calculator: Built-in health calculators and custom computation blocks
- Validation Rules: Field-level validation with custom error messages
- Page-by-Page: Traditional multi-page survey experience
- Continuous Scroll: Single-page scrollable layout
- Accordion: Collapsible sections for better organization
- Tabs: Tabbed interface for easy navigation
- Stepper: Step-by-step progression with visual indicators
- Full Page: Immersive full-screen survey experience
- 7 Built-in Themes: Default, Minimal, Colorful, Modern, Corporate, Dark, and Custom
- Complete Customization: Control every aspect of styling from colors to typography
- Dark Mode Support: Built-in dark/light mode toggle
- Responsive Design: Mobile-first approach with touch-friendly interactions
- CSS-in-JS: Tailwind CSS integration with theme variables
- Swipe Navigation: Touch gestures for mobile navigation
- Responsive Layouts: Optimized for all screen sizes
- Mobile-Specific Controls: Touch-friendly buttons and interactions
- Progressive Web App: Offline capability and app-like experience
- TypeScript Support: Full type safety and IntelliSense
- Workspace Architecture: Monorepo with separate builder and renderer packages
- Unified Block System: Single-file block definitions with
renderBlockfor unified rendering - Block Registry: Global block registration with
registerBlock()andgetBlockDefinition() - Extensible Architecture: Easy to add custom block types with full builder/renderer support
- Theme System: Comprehensive theming with CSS variables
- Modern Stack: React 19, Next.js 15, Tailwind CSS 4
This project follows a monorepo structure with two main components:
- Builder Interface (
/builder/) - Visual survey creation with drag-and-drop - Demo Interface (
/demo/) - Interactive survey renderer with JSON upload - Landing Page (
/) - Project overview and sample survey demonstration
- Builder Components (
/src/builder/) - Visual survey creation interface - Renderer Components (
/src/renderer/) - Survey form rendering engine - Block Definitions (
/src/builder/blocks/) - Individual form element types - Layout System (
/src/renderer/layouts/) - Different survey presentation modes - Theme Engine (
/src/themes/) - Comprehensive styling system
The survey builder includes 18+ predefined block types:
- Text Input: Single-line text fields with validation
- Textarea: Multi-line text areas
- Select Dropdown: Single and multi-select dropdowns
- Radio Buttons: Single-choice selection
- Checkboxes: Multiple-choice selection
- Selectable Boxes: Visual selection cards with auto-continue
- Range Slider: Numeric range selection
- Date Picker: Date/time selection with calendar
- File Upload: File attachment with type validation
- Matrix: Grid-based questions (Likert scales, rating matrices)
- Conditional: Dynamic blocks that appear based on logic
- Calculated Field: Computed values based on other responses
- BMI Calculator: Health assessment with automatic BMI calculation
- Checkout: Contact information and payment collection
- Authentication: User login/registration forms
- HTML: Rich content with custom HTML
- Markdown: Formatted text with Markdown support
- Script: Custom JavaScript execution
Comprehensive theming with 7 built-in themes:
// Available themes
type SurveyTheme =
| "default" // Clean, professional gray theme
| "minimal" // Simplified, typography-focused
| "colorful" // Vibrant, engaging colors
| "modern" // Contemporary design with gradients
| "corporate" // Professional business theme
| "dark" // Dark mode optimized
| "custom"; // Fully customizableEach theme controls:
- Colors: Primary, secondary, accent, background, text, borders
- Typography: Font sizes, weights, line heights
- Spacing: Margins, padding, component sizing
- Components: Buttons, inputs, cards, progress bars
- Animations: Transitions and interactive effects
- Node.js 18+
- npm, yarn, or bun package manager
- Clone the repository
git clone https://github.com/UNISELL-DEV/react-survey-builder.git
cd react-survey-builder- Install dependencies
bun install- Start the development server
bun dev- Open your browser Navigate to http://localhost:3000
bun run dev # Start development server with Turbopack
bun run build # Build the application
bun run start # Start production server
bun run lint # Run Next.js lintingcd src/packages/survey-form-package
bun run build # Build the package using tsup
bun run dev # Build package in watch mode
bun run lint # Run Biome lintingimport { SurveyForm } from 'survey-form-package';
function MyApp() {
const surveyData = {
rootNode: {
type: "section",
name: "Customer Feedback",
items: [
{
type: "set",
name: "Contact Information",
items: [
{
type: "textfield",
fieldName: "name",
label: "Full Name",
placeholder: "Enter your full name"
},
{
type: "selectablebox",
fieldName: "rating",
label: "How satisfied are you?",
options: [
{ id: "very-satisfied", label: "Very Satisfied", value: "5" },
{ id: "satisfied", label: "Satisfied", value: "4" },
{ id: "neutral", label: "Neutral", value: "3" },
{ id: "dissatisfied", label: "Dissatisfied", value: "2" },
{ id: "very-dissatisfied", label: "Very Dissatisfied", value: "1" }
]
}
]
}
]
}
};
return (
<SurveyForm
survey={surveyData}
theme="modern"
layout="page-by-page"
progressBar={{
type: 'percentage',
showPercentage: true,
position: 'top'
}}
onSubmit={(data) => console.log('Survey submitted:', data)}
onChange={(data) => console.log('Data changed:', data)}
/>
);
}The survey package now uses a unified block architecture where each block contains both builder and renderer components in a single definition. This makes it easier to create, maintain, and extend blocks.
import React, { useEffect } from 'react';
import { BlockDefinition, registerBlock } from 'survey-form-package';
const CustomRatingBlock: BlockDefinition = {
type: 'star-rating',
name: 'Star Rating',
description: 'Visual star rating component',
icon: <StarIcon className="w-4 h-4" />,
defaultData: {
type: 'star-rating',
fieldName: 'rating',
label: 'Rate your experience',
maxStars: 5,
allowHalfStars: true
},
// BUILDER COMPONENTS
renderItem: ({ data }) => (
// How block appears in builder preview
<StarRatingComponent maxStars={data.maxStars} disabled />
),
renderFormFields: ({ data, onUpdate }) => (
// Configuration form in builder
<div className="space-y-4">
<div>
<label>Label</label>
<input
value={data.label || ''}
onChange={(e) => onUpdate?.({ ...data, label: e.target.value })}
/>
</div>
<div>
<label>Maximum Stars</label>
<input
type="number"
value={data.maxStars || 5}
onChange={(e) => onUpdate?.({ ...data, maxStars: parseInt(e.target.value) })}
/>
</div>
</div>
),
renderPreview: () => (
// Small preview in block library
<div className="flex justify-center">
<StarRatingComponent maxStars={5} value={3} disabled />
</div>
),
// RENDERER COMPONENT - NEW UNIFIED APPROACH
renderBlock: ({ block, value, onChange, error, disabled }) => (
// How block renders in actual surveys
<div className="space-y-2">
{block.label && (
<label className="block text-sm font-medium">
{block.label}
</label>
)}
<StarRatingComponent
value={value || 0}
maxStars={block.maxStars || 5}
allowHalfStars={block.allowHalfStars}
onChange={onChange}
disabled={disabled}
/>
{error && <div className="text-red-500 text-sm">{error}</div>}
</div>
),
// VALIDATION
validate: (data) => {
if (!data.fieldName) return "Field name is required";
return null;
},
validateValue: (value, data) => {
if (data.required && !value) return "Rating is required";
return null;
},
};
// Register the custom block
function MyApp() {
useEffect(() => {
registerBlock(CustomRatingBlock);
}, []);
return (
<SurveyBuilder
blockDefinitions={[...StandardBlocks, CustomRatingBlock]}
// ... other props
/>
);
}- β Single Source of Truth: One file defines both builder and renderer behavior
- β Easier Maintenance: Changes only need to be made in one place
- β Better Type Safety: Shared interfaces ensure consistency
- β Simplified Extension: Custom blocks only need one implementation
- β Validation Consolidation: Both config and value validation in one place
All blocks use the unified system and support both builder and renderer functionality:
| Block Type | Description | Input Type |
|---|---|---|
textfield |
Single line text input | Text |
textarea |
Multi-line text area | Text |
radio |
Single choice selection | Option |
checkbox |
Multiple choice selection | Array |
select |
Dropdown selection | Option |
range |
Slider/range input | Number |
datepicker |
Date selection | Date |
fileupload |
File upload | File |
matrix |
Grid/table questions | Object |
selectablebox |
Visual selection boxes | Option |
markdown |
Rich text content | N/A |
html |
Raw HTML content | N/A |
script |
Custom JavaScript | N/A |
auth |
Authentication forms | Object |
bmiCalculator |
BMI calculation | Number |
calculated |
Dynamic calculations | Number |
conditional |
Conditional logic | Any |
checkout |
Payment forms | Object |
import { registerBlock, unregisterBlock, getBlockDefinition } from 'survey-form-package';
// Register a custom block
registerBlock(MyCustomBlock);
// Get a registered block
const blockDef = getBlockDefinition('my-custom-type');
// Unregister a block
unregisterBlock('my-custom-type');- π Custom Blocks Guide - Comprehensive guide for creating custom blocks
- π Block Migration Guide - Migration status and legacy block information
// Example: Show different questions based on user type
const conditionalSurvey = {
rootNode: {
type: "section",
name: "User Assessment",
items: [
{
type: "set",
name: "User Type",
items: [
{
type: "selectablebox",
fieldName: "userType",
label: "What type of user are you?",
options: [
{ id: "beginner", label: "Beginner", value: "beginner" },
{ id: "intermediate", label: "Intermediate", value: "intermediate" },
{ id: "advanced", label: "Advanced", value: "advanced" }
],
navigationRules: [
{
condition: "userType == 'beginner'",
target: "beginner-questions-page-id",
isPage: true
},
{
condition: "userType == 'advanced'",
target: "advanced-questions-page-id",
isPage: true
}
]
}
]
}
]
}
};interface SurveyFormProps {
survey: {
rootNode: NodeData;
localizations?: LocalizationMap;
theme?: ThemeDefinition;
};
onSubmit?: (data: Record<string, any>) => void;
onChange?: (data: Record<string, any>) => void;
onPageChange?: (pageIndex: number, totalPages: number) => void;
defaultValues?: Record<string, any>;
language?: string;
theme?: SurveyTheme;
layout?: SurveyLayout;
progressBar?: ProgressBarOptions;
navigationButtons?: NavigationButtonsOptions;
autoScroll?: boolean;
autoFocus?: boolean;
showSummary?: boolean;
className?: string;
logo?: ReactNode;
enableDebug?: boolean;
}type SurveyLayout =
| "page-by-page" // Traditional multi-page navigation
| "continuous" // Single scrollable page
| "accordion" // Collapsible sections
| "tabs" // Tabbed interface
| "stepper" // Step-by-step with progress
| "fullpage"; // Full-screen experienceinterface ProgressBarOptions {
type?: "bar" | "dots" | "numbers" | "percentage";
showPercentage?: boolean;
showStepInfo?: boolean;
showStepTitles?: boolean;
position?: "top" | "bottom";
animation?: boolean;
}The project includes a comprehensive sample survey demonstrating:
- Multi-page navigation with conditional routing
- Selectable box questions with auto-continue functionality
- Conditional logic based on user responses
- Custom HTML result pages with tailored recommendations
- Checkout integration for lead capture
- Professional styling with consistent theming
Key features demonstrated:
- Career assessment with personalized recommendations
- Educational background evaluation
- Skills and interests mapping
- Dynamic page routing based on responses
- Custom result pages with actionable advice
react-survey-builder/
βββ src/
β βββ app/ # Next.js application
β β βββ builder/ # Visual survey builder
β β βββ demo/ # Interactive demo
β β βββ page.tsx # Landing page with sample survey
β βββ packages/
β β βββ survey-form-package/ # Core survey package
β β βββ src/
β β β βββ builder/ # Survey builder components
β β β β βββ blocks/ # Block definitions
β β β β βββ survey/ # Builder interface
β β β β βββ common/ # Shared components
β β β βββ renderer/ # Survey renderer
β β β β βββ layouts/ # Layout components
β β β β βββ renderers/ # Block renderers
β β β βββ components/ # UI components
β β β βββ context/ # React contexts
β β β βββ hooks/ # Custom hooks
β β β |ββ themes/ # Theme definitions
β β β βββ utils/ # Utility functions
β β β βββ types.ts # TypeScript definitions
β β βββ package.json
β βββ components/ # Shared UI components
βββ public/ # Static assets
βββ package.json # Main package configuration
- Create block definition
// src/packages/survey-form-package/src/builder/blocks/YourCustomBlock.tsx
import { BlockDefinition } from '../../types';
export const YourCustomBlock: BlockDefinition = {
type: 'your-custom-type',
name: 'Your Custom Block',
description: 'Description of your block',
icon: <YourIcon />,
defaultData: {
type: 'your-custom-type',
// default properties
},
renderItem: ({ data, value, onChange }) => {
// Render logic for the actual form
},
renderFormFields: ({ data, onUpdate }) => {
// Render configuration form for the builder
},
renderPreview: () => {
// Render preview in block library
}
};- Add corresponding renderer
// src/packages/survey-form-package/src/renderer/renderers/YourCustomRenderer.tsx
export const YourCustomRenderer: React.FC<BlockRendererProps> = ({
block,
value,
onChange
}) => {
// Render logic for the survey form
};- Register in index files
// Add to src/packages/survey-form-package/src/builder/blocks/index.ts
export { YourCustomBlock } from './YourCustomBlock';
// Add to BlockRenderer.tsx
import { YourCustomRenderer } from './YourCustomRenderer';- Framework: React 19 with Next.js 15
- Build Tool: Turbopack for fast development
- Styling: Tailwind CSS 4 with CSS-in-JS
- UI Components: Radix UI primitives
- Animations: Framer Motion
- Drag & Drop: @dnd-kit
- Type Safety: TypeScript 5
- Package Management: bun workspaces
- Bundling: tsup for package builds
- Tree Shaking: Modular imports and exports
- Code Splitting: Dynamic imports for layouts and renderers
- Memoization: React.memo and useMemo for expensive calculations
- Lazy Loading: Components loaded on demand
- Bundle Analysis: Optimized package sizes
Main component for rendering surveys.
<SurveyForm
survey={surveyData}
theme="modern"
layout="page-by-page"
onSubmit={handleSubmit}
onChange={handleChange}
progressBar={{ type: 'percentage', position: 'top' }}
navigationButtons={{ showPrevious: true, showNext: true }}
/>Visual builder component for creating surveys.
<SurveyBuilder
blockDefinitions={[...StandardBlocks, ...customBlocks]}
nodeDefinitions={StandardNodes}
onDataChange={handleDataChange}
initialData={existingSurvey}
/>const {
values,
errors,
currentPage,
totalPages,
goToPage,
goToNextPage,
goToPreviousPage,
submit,
isValid
} = useSurveyForm(survey, options);const {
enableSwipe,
handleSwipeLeft,
handleSwipeRight,
swipeDirection
} = useMobileNavigation({
onSwipeLeft: goToNextPage,
onSwipeRight: goToPreviousPage
});We welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Run linting:
bun run lint - Submit a pull request
This project is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License.
- β Permitted: Open source projects, educational use, personal projects
- β Requires License: Commercial use, SaaS products, client projects
For commercial licensing, please contact the maintainers.
- Radix UI for accessible component primitives
- Tailwind CSS for utility-first styling
- Framer Motion for smooth animations
- @dnd-kit for drag-and-drop functionality
- React and Next.js teams for excellent frameworks
- π§ Email: [sayeed99@live.com]
- π¬ Discussions: GitHub Discussions
- π Issues: GitHub Issues
This project is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License. You may use the code for open source or other non-commercial purposes. For commercial use or projects where you will charge end users, please contact the maintainers to obtain a commercial license.