# Form Builder Grid System - Complete Reference
## Overview
The form builder uses an intelligent 12-column CSS Grid system that automatically manages component placement and provides intuitive width selection through visual previews and smart recommendations. This system replaces technical percentages with user-friendly names and includes automatic gap-filling optimization.
## Grid Architecture
### CSS Grid Foundation
```css
.grid-container {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-auto-flow: row dense; /* Enables automatic gap filling */
column-gap: 16px;
row-gap: 16px;
width: 100%;
}
```
### Component Grid Placement
```css
.form-component {
grid-column: span 12; /* Default to full width */
width: 100% !important; /* Force width within grid cell */
transition: all 0.2s ease;
}
```
## Width Options System
### Available Width Options
| Name | Percentage | Grid Columns | Grid Span | Use Cases |
|--------|------------|--------------|--------------|-----------|
| Narrow | 25% | 3 of 12 | `span 3` | Small inputs like age, zip codes, short codes |
| Small | 33% | 4 of 12 | `span 4` | Short text fields, city names, grouped inputs |
| Medium | 50% | 6 of 12 | `span 6` | Names, phone numbers, paired inputs |
| Wide | 75% | 9 of 12 | `span 9` | Addresses, URLs, prominent fields |
| Full | 100% | 12 of 12 | `span 12` | Text areas, headings, single-column layouts |
### Width Selection Interface
#### Visual Grid Preview
Each width option displays a mini 12-column grid preview:
```vue
```
#### Current Selection Feedback
The interface shows:
- Current width name (e.g., "Medium")
- Grid columns used (e.g., "6 of 12 columns")
- Visual representation of current selection
- Percentage equivalent for technical reference
## Smart Recommendation System
### Field Type Recommendations
The system automatically suggests optimal widths based on component type:
#### Narrow Fields (25% - 3 columns)
**Recommended for**: Small, precise inputs
- `number`: Age, quantity, counts
- `date`: Birth dates, deadlines
- `time`: Appointment times
- `color`: Color picker inputs
- `otp`: Verification codes
```javascript
const narrowRecommended = ['number', 'date', 'time', 'color', 'otp']
```
#### Small Fields (33% - 4 columns)
**Recommended for**: Short text inputs
- `text`: Names, titles, short answers
```javascript
const smallRecommended = ['text']
```
#### Medium Fields (50% - 6 columns)
**Recommended for**: Standard form inputs
- `email`: Email addresses
- `tel`: Phone numbers
- `password`: Password fields
- `mask`: Formatted inputs (SSN, phone)
- `select`: Dropdown selections
- `datetime-local`: Combined date/time
```javascript
const mediumRecommended = ['email', 'tel', 'password', 'mask', 'select', 'datetime-local']
```
#### Wide Fields (75% - 9 columns)
**Recommended for**: Longer inputs requiring more space
- `url`: Website addresses
- `file`: File upload fields
- `dropzone`: Drag & drop upload areas
```javascript
const wideRecommended = ['url', 'file', 'dropzone']
```
#### Full Width Fields (100% - 12 columns)
**Recommended for**: Content and multi-option components
- `textarea`: Multi-line text areas
- `heading`: Section headings
- `paragraph`: Descriptive text
- `checkbox`: Checkbox groups
- `radio`: Radio button groups
- `range`: Range sliders
- `switch`: Toggle switches
- `button`: Action buttons
- `info-display`: Information displays
```javascript
const fullRecommended = [
'textarea', 'heading', 'paragraph', 'checkbox',
'radio', 'range', 'switch', 'button', 'info-display'
]
```
### Visual Recommendation Indicators
- **Green Ring**: Recommended options have green highlighting
- **Selection State**: Current choice highlighted in blue
- **Combined State**: Selected + recommended shows green background with checkmark
- **Recommendation Badge**: "Recommended" text appears next to optimal choices
## Smart Grid Placement Algorithm
### Optimal Placement Logic
The system automatically finds the best position for new components:
```javascript
findOptimalGridPlacement() {
if (this.formComponents.length === 0) {
// First component - full width
return {
gridColumn: 'span 12',
rowIndex: 0,
width: '100%'
}
}
// Group components by their implicit rows
const rows = this.analyzeGridRows()
// Find row with remaining space
const rowWithSpace = rows.find(row => row.remainingSpace > 0)
if (rowWithSpace) {
// Use remaining space in existing row
const remainingColumns = rowWithSpace.remainingSpace
const widthPercent = this.columnsToPercentage(remainingColumns)
return {
gridColumn: `span ${remainingColumns}`,
rowIndex: rows.indexOf(rowWithSpace),
width: `${widthPercent}%`
}
} else {
// Create new row
return {
gridColumn: 'span 12',
rowIndex: rows.length,
width: '100%'
}
}
}
```
### Row Analysis
```javascript
analyzeGridRows() {
const rows = []
let currentRowSpace = 12
this.formComponents.forEach(component => {
const spanMatch = component.props.gridColumn?.match(/span\s+(\d+)/) || []
const columnSpan = parseInt(spanMatch[1]) || 12
if (columnSpan <= currentRowSpace) {
// Add to current row
currentRowSpace -= columnSpan
} else {
// Start new row
rows.push({ remainingSpace: currentRowSpace })
currentRowSpace = 12 - columnSpan
}
})
return rows
}
```
## Grid Layout Optimization
### Automatic Gap Filling
The `grid-auto-flow: row dense` CSS property enables automatic gap filling:
- Components automatically fill available spaces
- No manual positioning required
- Optimal use of screen real estate
### Layout Optimization Algorithm
```javascript
optimizeGridLayout() {
const rows = this.groupComponentsByRows()
rows.forEach(row => {
if (row.remainingSpace > 0) {
this.distributeRemainingSpace(row)
}
})
}
distributeRemainingSpace(row) {
if (row.components.length === 1 && row.remainingSpace > 0) {
// Expand single component to fill row
const comp = row.components[0]
this.updateComponentSize(comp.component, 12)
} else if (row.components.length > 1) {
// Distribute space proportionally
const extraSpanPerComponent = Math.floor(row.remainingSpace / row.components.length)
let remainingExtraSpan = row.remainingSpace % row.components.length
row.components.forEach(comp => {
let extraSpan = extraSpanPerComponent
if (remainingExtraSpan > 0) {
extraSpan += 1
remainingExtraSpan--
}
const newSpan = comp.span + extraSpan
this.updateComponentSize(comp.component, newSpan)
})
}
}
```
## Collapsible Panel Integration
### Quick Width Selector
The collapsible panel includes a compact width selector:
```vue
```
### Compact Options
```javascript
const compactWidthOptions = [
{ name: 'S', value: 25, gridColumns: 3, description: 'Small (25%)' },
{ name: 'M', value: 50, gridColumns: 6, description: 'Medium (50%)' },
{ name: 'L', value: 75, gridColumns: 9, description: 'Large (75%)' },
{ name: 'XL', value: 100, gridColumns: 12, description: 'Extra Large (100%)' }
]
```
## Grid Component Implementation
### Component Props Structure
```typescript
interface ComponentProps {
width: string // e.g., "50%"
gridColumn: string // e.g., "span 6"
label?: string
name?: string
// ... other props
}
```
### Width Calculation Functions
```javascript
// Convert percentage to grid columns
const percentageToGridColumns = (percentage) => {
const mapping = {
25: 3, // 3/12 = 25%
33: 4, // 4/12 = 33.33%
50: 6, // 6/12 = 50%
66: 8, // 8/12 = 66.67%
75: 9, // 9/12 = 75%
100: 12 // 12/12 = 100%
}
return mapping[percentage] || Math.round((percentage / 100) * 12)
}
// Convert grid columns to percentage
const gridColumnsToPercentage = (columns) => {
const mapping = {
3: 25, // 3/12 = 25%
4: 33, // 4/12 = 33.33%
6: 50, // 6/12 = 50%
8: 66, // 8/12 = 66.67%
9: 75, // 9/12 = 75%
12: 100 // 12/12 = 100%
}
return mapping[columns] || Math.round((columns / 12) * 100)
}
// Set component width with grid sync
const setComponentWidth = (percentage, gridColumns) => {
component.props.width = `${percentage}%`
component.props.gridColumn = `span ${gridColumns}`
}
```
## Responsive Behavior
### Mobile Optimization
```css
@media (max-width: 768px) {
.grid-container {
grid-template-columns: 1fr; /* Single column on mobile */
column-gap: 0;
}
.form-component {
grid-column: span 1 !important; /* Force single column */
}
}
```
### Tablet Optimization
```css
@media (min-width: 769px) and (max-width: 1024px) {
.grid-container {
grid-template-columns: repeat(8, 1fr); /* 8 columns on tablet */
}
.form-component[style*="span 12"] {
grid-column: span 8 !important; /* Adjust full-width components */
}
}
```
## Resize Handle System
### Interactive Resizing
```vue
```
### Resize Logic with Snap-to-Grid
```javascript
const handleResize = (event) => {
const deltaX = event.clientX - initialX.value
const container = document.querySelector('.grid-container')
const containerWidth = container.offsetWidth
const deltaPercentage = (deltaX / containerWidth) * 100
let newWidth = initialWidth.value + deltaPercentage
newWidth = Math.max(25, Math.min(100, newWidth))
// Snap to standard widths
const standardWidths = [25, 33, 50, 66, 75, 100]
for (const std of standardWidths) {
if (Math.abs(newWidth - std) < 5) {
newWidth = std
break
}
}
// Convert to grid columns and update
const gridColumns = percentageToGridColumns(newWidth)
updateComponentSize(component, newWidth, gridColumns)
}
```
## CSS Styling Reference
### Grid Container Styles
```css
.grid-container {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-auto-flow: row dense;
column-gap: 16px;
row-gap: 16px;
width: 100%;
padding: 0;
box-sizing: border-box;
}
```
### Width Selector Modal Styles
```css
.width-option {
@apply border border-gray-200 rounded-lg p-4 transition-all duration-200 hover:border-blue-300 hover:bg-blue-50 cursor-pointer flex items-center space-x-4;
}
.width-option.selected {
@apply border-blue-500 bg-blue-50 ring-2 ring-blue-200;
}
.width-option.recommended {
@apply ring-2 ring-green-200 border-green-300;
}
.width-option.selected.recommended {
@apply border-green-500 bg-green-50 ring-2 ring-green-200;
}
```
### Grid Preview Styles
```css
.grid-container-mini {
@apply grid grid-cols-12 gap-1 w-32;
}
.grid-cell {
@apply h-2 rounded-sm transition-colors duration-200;
}
.grid-cell.active {
@apply bg-blue-500;
}
.grid-cell.inactive {
@apply bg-gray-200;
}
```
### Quick Selector Styles
```css
.width-selector-compact {
@apply flex space-x-1;
}
.width-btn {
@apply flex-1 px-2 py-1.5 text-xs font-medium text-center rounded-md border border-gray-200 bg-white hover:border-blue-300 hover:bg-blue-50 transition-colors duration-200;
}
.width-btn.active {
@apply border-blue-500 bg-blue-50 text-blue-700 ring-1 ring-blue-200;
}
```
## Best Practices
### Grid Layout Design
1. **Start Simple**: Begin with recommended widths
2. **Mix Widths**: Combine different widths for visual interest
3. **Logical Grouping**: Use consistent widths for related fields
4. **Visual Balance**: Avoid too many full-width fields in sequence
5. **Mobile-First**: Consider how layouts adapt on smaller screens
### Performance Considerations
1. **Grid Optimization**: Use the automatic optimization feature
2. **Component Limits**: Keep forms under 50 components for best performance
3. **Responsive Testing**: Test across different screen sizes
4. **Browser Support**: Ensure CSS Grid polyfills for older browsers
### User Experience Guidelines
1. **Intuitive Widths**: Trust the recommendation system
2. **Visual Feedback**: Use the grid preview for precision
3. **Consistent Patterns**: Establish width patterns across forms
4. **Progressive Enhancement**: Start with basics, add complexity gradually
## Troubleshooting
### Common Issues
**Grid Layout Not Working**
- Check CSS Grid browser support
- Verify `grid-template-columns` is applied
- Ensure components have valid `gridColumn` values
**Components Overlapping**
- Check for invalid span values (must be 1-12)
- Verify total spans in row don't exceed 12
- Use grid optimization to fix layouts
**Responsive Issues**
- Test media query breakpoints
- Verify mobile-specific grid rules
- Check component width calculations
**Performance Problems**
- Reduce number of components
- Use virtual scrolling for large forms
- Optimize grid calculations
### Debugging Tools
```javascript
// Debug grid layout
const debugGridLayout = () => {
const rows = groupComponentsByRows()
console.table(rows.map(row => ({
components: row.components.length,
remainingSpace: row.remainingSpace,
totalSpan: 12 - row.remainingSpace
})))
}
// Validate component grid properties
const validateGridProps = (component) => {
const span = component.props.gridColumn?.match(/span\s+(\d+)/)?.[1]
const width = parseInt(component.props.width)
console.log({
id: component.id,
span: parseInt(span),
width: width,
valid: span >= 1 && span <= 12 && width > 0 && width <= 100
})
}
```
## Migration Guide
### Upgrading from Percentage-Only System
1. **Update Component Props**:
```javascript
// Old system
component.props.width = "50%"
// New system
component.props.width = "50%"
component.props.gridColumn = "span 6"
```
2. **Migrate Existing Forms**:
```javascript
const migrateFormToGrid = (form) => {
return {
...form,
components: form.components.map(component => ({
...component,
props: {
...component.props,
gridColumn: component.props.gridColumn ||
`span ${percentageToGridColumns(parseInt(component.props.width) || 100)}`
}
}))
}
}
```
3. **Update CSS**:
```css
/* Remove old percentage-based widths */
.form-component {
/* width: var(--component-width); // Remove this */
grid-column: var(--grid-column); /* Add this */
}
```
---
*This grid system documentation reflects the complete implementation including visual selection, smart recommendations, automatic optimization, and responsive behavior.*
**Last updated**: December 2024