This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- @vitejs/plugin-react uses Babel for Fast Refresh
- @vitejs/plugin-react-swc uses SWC for Fast Refresh
Here's an overview of the key architectural and implementation decisions made.
-
Component-Based Architecture: The application adheres to a component-based architecture, leveraging React components such as
FormBuilder,PreviewForm,FieldEditor, andFieldPreview. -
State Management: Core application state, including
formConfig(the form's structural definition) and UI flags likeshowPreviewandshowSuccess, is managed using React'suseStatehook.useCallbackis employed to memoize functions, optimizing performance by preventing unnecessary re-renders of child components. -
Uncontrolled Components for Form Submission: For form data collection in
PreviewForm, an uncontrolled component approach was chosen. Instead of managing input values viauseStateandonChangefor every keystroke,useRefis utilized to access the DOM form element directly upon submission. This design decision centralizes data extraction logic withinPreviewForm'shandleSubmitfunction, simplifying the individualFieldPreviewcomponents by allowing them to manage their own internal state until submission. Data is then extracted usingHTMLFormElement.elementsandquerySelectorAllfor robust collection across various input types, including checkboxes (i dont like checkboxes). -
Dynamic Form Rendering: The
PreviewFormdynamically renders form fields based on theformConfigdefinition. This involves iterating throughformElementsand conditionally rendering the appropriateFieldPreviewcomponent (e.g.,TextFieldPreview,CheckboxFieldPreview) based on theelement.type. This approach ensures flexibility and extensibility for different form input types. -
Single-Page Application (SPA) Architecture: The entire application operates as a Single-Page Application. Navigation and view changes (e.g., switching between form builder and preview) are handled client-side through React component rendering and state updates.
-
Styling: Styling is managed using Tailwind CSS, adopting a utility-first approach. I have also followed GFE's fonts and brand colours :-)
The application is organized into a clear component hierarchy to manage complexity and promote reusability. Key directories and their primary components include:
-
src/pages/: Contains top-level page components that define the main views of the application.MainPage.tsx: The primary entry point for the application's UI, orchestrating the form builder, preview, and submission success states.
-
src/components/: Houses reusable UI components, further categorized by their function.builder/: Components related to the form building interface.FormBuilder.tsx: The main component for designing and configuring the form.EditForm.tsx: Manages the overall editing experience, including adding and reordering form elements.AddFormElements.tsx: Provides controls for adding new types of form fields.FormElement.tsx: A wrapper component for individual form elements in the editor, providing common actions like reordering and removal.
editors/: Components for editing the properties of specific form field types.FieldEditor.tsx: A generic wrapper for all field-specific editors.TextFieldEditor.tsx,ParagraphFieldEditor.tsx,CheckboxFieldEditor.tsx,SelectFieldEditor.tsx: Specific editors for each field type.
preview/: Components for displaying the live preview of the form.PreviewForm.tsx: Renders the complete form based on the current configuration, allowing user interaction.TextFieldPreview.tsx,ParagraphFieldPreview.tsx,CheckboxFieldPreview.tsx,SelectFieldPreview.tsx: Components that render the display-only version of each field type.
ui/: General-purpose UI components.Header.tsx: The application's navigation and action bar.
SubmitSuccess.tsx: Displays a success message and navigation options after form submission.
-
src/types.ts: Contains TypeScript type definitions and interfaces used across the application, ensuring type safety and clear data structures.
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
export default tseslint.config([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Remove tseslint.configs.recommended and replace with this
...tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
...tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
...tseslint.configs.stylisticTypeChecked,
// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])You can also install eslint-plugin-react-x and eslint-plugin-react-dom for React-specific lint rules:
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'
export default tseslint.config([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])