DEV Community

Pinoy Codie
Pinoy Codie

Posted on

JurisJS: Object DOM Formatting Best Practices: The Art of Readable Nested Structures

JurisJS Object DOM

Introduction

When working with Object DOM - representing user interfaces as JavaScript objects rather than template strings - one of the biggest challenges developers face is maintaining readability in deeply nested structures. Unlike HTML's self-documenting closing tags (</div>), JavaScript objects can quickly become an unreadable maze of closing brackets.

This article explores innovative formatting conventions that solve these readability problems, making Object DOM code as clear and maintainable as traditional HTML templates.

The Readability Problem

Consider this typical Object DOM structure without proper formatting:

// ❌ Hard to read and maintain
const component = {div:{className:'main',children:[{header:{className:'app-header',children:[{h1:{text:'My App'}},{nav:{children:[{a:{href:'/home',text:'Home'}},{a:{href:'/about',text:'About'}}]}}]}},{main:{className:'content',children:[{section:{children:[{h2:{text:'Welcome'}},{p:{text:'This is the main content'}}]}}]}}]}}
Enter fullscreen mode Exit fullscreen mode

Where does each component end? What's the structure? It's nearly impossible to read or debug.

The Juris Formatting Philosophy

The Juris framework (GitHub | NPM) introduced a revolutionary approach to Object DOM formatting with three core principles:

1. Static vs. Reactive Property Distinction

Rule: Static, short properties stay inline. Reactive or complex properties get new lines.

// ✅ Clear distinction between static and reactive
{div:{className:'user-card', id:'user-123',  // Static props: inline
  text: () => getState('user.displayName'),   // Reactive prop: new line
  style: () => ({                             // Complex reactive: new line
    backgroundColor: getState('theme.cardColor', '#white'),
    opacity: getState('user.isActive') ? 1 : 0.5
  }),
  onClick: () => selectUser()                 // Event handler: new line
}}
Enter fullscreen mode Exit fullscreen mode

Why this works: The visual formatting immediately communicates the nature of each property:

  • Inline = Won't change during component lifecycle
  • New line = Will update based on state or user interaction

2. End-Bracket Labeling

Rule: Add descriptive comments to closing brackets to create visual hierarchy.

// ✅ Clear structural hierarchy
{div:{className:'dashboard',
  children:[
    {header:{className:'dashboard-header',
      children:[
        {h1:{text:'Dashboard'}},
        {nav:{
          children:[
            {a:{href:'/home', text:'Home'}},
            {a:{href:'/reports', text:'Reports'}}
          ]
        }}//nav
      ]
    }}//header
    {main:{className:'dashboard-content',
      children:[
        {section:{className:'widgets',
          children: () => renderWidgets()
        }}//section.widgets
        {aside:{className:'sidebar',
          children: () => renderSidebar()
        }}//aside.sidebar
      ]
    }}//main
  ]
}}//div.dashboard
Enter fullscreen mode Exit fullscreen mode

Labeling variations:

  • }}//button - Simple tag name
  • }}//div.user-card - Tag with key class
  • }}//section.widgets - Tag with descriptive class
  • }}//header.app-header - Tag with component role

3. Compressed Object Structure

Rule: Minimize unnecessary whitespace while maintaining readability through strategic line breaks.

// ✅ Compressed but readable
{form:{className:'contact-form', onSubmit:handleSubmit,
  children:[
    {div:{className:'field-group',
      children:[
        {label:{htmlFor:'email', text:'Email'}},
        {input:{id:'email', type:'email', required:true,
          value: () => getState('form.email', ''),
          onInput: (e) => setState('form.email', e.target.value)
        }}
      ]
    }}//div.field-group
    {div:{className:'field-group',
      children:[
        {label:{htmlFor:'message', text:'Message'}},
        {textarea:{id:'message', rows:4,
          value: () => getState('form.message', ''),
          onInput: (e) => setState('form.message', e.target.value)
        }}
      ]
    }}//div.field-group
    {button:{type:'submit', className:'btn-primary',
      text: () => getState('form.isSubmitting') ? 'Sending...' : 'Send Message'
    }}//button
  ]
}}//form.contact-form
Enter fullscreen mode Exit fullscreen mode

Advanced Formatting Patterns

1. Children Array Formatting

When dealing with children arrays, use consistent indentation and labeling:

// ✅ Well-formatted children array
{div:{className:'product-grid',
  children:[
    // Static items
    {div:{className:'grid-header',
      children:[
        {h2:{text:'Products'}},
        {button:{className:'add-btn', text:'Add Product'}}
      ]
    }}//div.grid-header

    // Dynamic items with clear separation
    ...() => getState('products', []).map(product => ({
      div:{key:product.id, className:'product-card',
        children:[
          {img:{src:product.image, alt:product.name}},
          {h3:{text:product.name}},
          {p:{className:'price', text:`$${product.price}`}},
          {button:{text:'Add to Cart',
            onClick: () => addToCart(product.id)
          }}//button
        ]
      }//div.product-card
    })),

    // Footer section
    {div:{className:'grid-footer',
      children:[
        {p:{text: () => `Showing ${getState('products', []).length} products`}}
      ]
    }}//div.grid-footer
  ]
}}//div.product-grid
Enter fullscreen mode Exit fullscreen mode

2. Conditional Rendering Patterns

Format conditional logic clearly within the structure:

// ✅ Clear conditional formatting
{div:{className:'user-profile',
  children:[
    {div:{className:'profile-header',
      children:[
        {img:{src: () => getState('user.avatar'), alt:'Profile picture'}},
        {h2:{text: () => getState('user.name')}}
      ]
    }}//div.profile-header

    // Conditional premium features
    ...() => {
      const isPremium = getState('user.isPremium', false);
      return isPremium ? [
        {div:{className:'premium-badge',
          children:[
            {span:{text:'✨ Premium Member'}},
            {button:{text:'Manage Subscription',
              onClick: () => navigate('/subscription')
            }}//button
          ]
        }}//div.premium-badge
        {div:{className:'premium-features',
          children: () => renderPremiumFeatures()
        }}//div.premium-features
      ] : [
        {div:{className:'upgrade-prompt',
          children:[
            {p:{text:'Upgrade to unlock premium features'}},
            {button:{className:'btn-upgrade', text:'Upgrade Now',
              onClick: () => navigate('/upgrade')
            }}//button
          ]
        }}//div.upgrade-prompt
      ];
    }()
  ]
}}//div.user-profile
Enter fullscreen mode Exit fullscreen mode

3. Complex State Dependencies

Handle complex reactive patterns with clear formatting:

// ✅ Complex state handling with clear structure
{div:{className:'shopping-cart',
  children:[
    {div:{className:'cart-header',
      children:[
        {h2:{text:'Shopping Cart'}},
        {span:{className:'item-count',
          text: () => {
            const items = getState('cart.items', []);
            const count = items.reduce((sum, item) => sum + item.quantity, 0);
            return `${count} item${count !== 1 ? 's' : ''}`;
          }
        }}
      ]
    }}//div.cart-header

    {div:{className:'cart-items',
      children: () => {
        const items = getState('cart.items', []);

        if (items.length === 0) {
          return [{div:{className:'empty-cart',
            children:[
              {p:{text:'Your cart is empty'}},
              {button:{text:'Continue Shopping',
                onClick: () => navigate('/products')
              }}//button
            ]
          }}];//div.empty-cart
        }

        return items.map(item => ({
          div:{key:item.id, className:'cart-item',
            children:[
              {img:{src:item.image, alt:item.name}},
              {div:{className:'item-details',
                children:[
                  {h4:{text:item.name}},
                  {p:{className:'item-price', text:`$${item.price}`}}
                ]
              }}//div.item-details
              {div:{className:'quantity-controls',
                children:[
                  {button:{text:'-',
                    onClick: () => updateQuantity(item.id, item.quantity - 1)
                  }},
                  {span:{text:item.quantity}},
                  {button:{text:'+',
                    onClick: () => updateQuantity(item.id, item.quantity + 1)
                  }}
                ]
              }}//div.quantity-controls
              {button:{className:'remove-item', text:'Remove',
                onClick: () => removeFromCart(item.id)
              }}//button
            ]
          }//div.cart-item
        }));
      }
    }}//div.cart-items

    {div:{className:'cart-footer',
      children:[
        {div:{className:'cart-total',
          children:[
            {span:{text:'Total: '}},
            {strong:{
              text: () => {
                const items = getState('cart.items', []);
                const total = items.reduce((sum, item) => 
                  sum + (item.price * item.quantity), 0
                );
                return `$${total.toFixed(2)}`;
              }
            }}
          ]
        }}//div.cart-total
        {button:{className:'checkout-btn',
          disabled: () => getState('cart.items', []).length === 0,
          text:'Proceed to Checkout',
          onClick: () => navigate('/checkout')
        }}//button
      ]
    }}//div.cart-footer
  ]
}}//div.shopping-cart
Enter fullscreen mode Exit fullscreen mode

Formatting Tools and Conventions

1. Indentation Rules

  • Use 2 spaces for each nesting level
  • Align object properties at the same level
  • Break before complex functions but keep simple ones inline
// ✅ Consistent indentation
{div:{className:'container',
  children:[
    {header:{role:'banner',
      children:[
        {h1:{text:'Site Title'}},
        {nav:{
          children: () => getNavigationItems()  // Complex function: new line
        }}//nav
      ]
    }}//header
    {main:{role:'main', className:'content',  // Simple props: inline
      children: () => renderMainContent()     // Complex function: new line
    }}//main
  ]
}}//div.container
Enter fullscreen mode Exit fullscreen mode

2. Property Ordering

Establish a consistent order for properties:

  1. Structural properties (key, className, id)
  2. Semantic properties (role, aria-*, htmlFor)
  3. Static content (text, src, href)
  4. Reactive content (dynamic text, style)
  5. Event handlers (onClick, onInput, etc.)
  6. Children (always last)
// ✅ Consistent property ordering
{button:{
  key: item.id,                              // 1. Structural
  className: 'action-btn',                   // 1. Structural
  role: 'button',                            // 2. Semantic
  'aria-label': 'Add to favorites',          // 2. Semantic
  type: 'button',                            // 3. Static content
  disabled: () => getState('ui.isLoading'),  // 4. Reactive content
  onClick: () => toggleFavorite(item.id)     // 5. Event handlers
}}//button
Enter fullscreen mode Exit fullscreen mode

3. Comment Conventions

Use comments strategically to explain complex logic:

// ✅ Strategic commenting
{div:{className:'data-visualization',
  children:[
    // Chart header with dynamic title
    {div:{className:'chart-header',
      children:[
        {h3:{
          text: () => {
            const timeRange = getState('chart.timeRange', '7d');
            const dataType = getState('chart.dataType', 'revenue');
            return `${dataType} over ${timeRange}`;
          }
        }}
      ]
    }}//div.chart-header

    // Main chart area - lazy loaded for performance
    {div:{className:'chart-container',
      children: () => {
        const isVisible = getState('chart.isVisible', false);
        return isVisible ? [ChartComponent(context)] : [
          {div:{className:'chart-placeholder',
            children:[
              {button:{text:'Load Chart',
                onClick: () => setState('chart.isVisible', true)
              }}//button
            ]
          }}//div.chart-placeholder
        ];
      }
    }}//div.chart-container
  ]
}}//div.data-visualization
Enter fullscreen mode Exit fullscreen mode

Common Formatting Mistakes

1. Inconsistent Line Breaking

// ❌ Inconsistent formatting
{div:{className:'card',text: () => getState('title'),
style: {padding: '20px'},
  children:[{p:{text:'Content'}}]
}}

// ✅ Consistent formatting
{div:{className:'card',
  text: () => getState('title'),
  style: {padding: '20px'},
  children:[
    {p:{text:'Content'}}
  ]
}}//div.card
Enter fullscreen mode Exit fullscreen mode

2. Missing or Inconsistent Labels

// ❌ Missing labels make structure unclear
{div:{
  children:[
    {header:{
      children:[{h1:{text:'Title'}}]
    }}
    {main:{
      children:[{p:{text:'Content'}}]
    }}
  ]
}}

// ✅ Clear labeling shows structure
{div:{className:'page',
  children:[
    {header:{
      children:[
        {h1:{text:'Title'}}
      ]
    }}//header
    {main:{
      children:[
        {p:{text:'Content'}}
      ]
    }}//main
  ]
}}//div.page
Enter fullscreen mode Exit fullscreen mode

3. Overcomplicating Simple Structures

// ❌ Unnecessarily complex for simple content
{div:{
  className: 'simple-card',
  children: [
    {
      h3: {
        text: 'Simple Title'
      }
    },
    {
      p: {
        text: 'Simple description'
      }
    }
  ]
}}

// ✅ Keep simple structures simple
{div:{className:'simple-card',
  children:[
    {h3:{text:'Simple Title'}},
    {p:{text:'Simple description'}}
  ]
}}//div.simple-card
Enter fullscreen mode Exit fullscreen mode

Team Conventions and Style Guides

1. Establishing Team Standards

Create a style guide for your team:

// Team Style Guide Example

// Property ordering (always follow this order):
// 1. key, className, id
// 2. role, aria-*, semantic attributes  
// 3. type, src, href, static props
// 4. reactive props (functions)
// 5. event handlers
// 6. children (always last)

// Labeling conventions:
// - Simple tags: }}//button
// - With main class: }}//div.user-card  
// - With semantic role: }}//section.hero
// - With state context: }}//form.login-form

// Line breaking rules:
// - Static props under 50 chars: inline
// - Functions and reactive props: new line
// - Complex objects: new line
// - Event handlers: new line
Enter fullscreen mode Exit fullscreen mode

2. Linting and Automated Formatting

Consider creating ESLint rules or Prettier configurations:

// .eslintrc.js - Custom rules for Object DOM
module.exports = {
  rules: {
    // Enforce consistent Object DOM formatting
    'object-dom/consistent-labeling': 'error',
    'object-dom/reactive-on-new-line': 'error',
    'object-dom/property-ordering': 'warn'
  }
};
Enter fullscreen mode Exit fullscreen mode

Performance Considerations

1. Formatting for Optimization

Good formatting can actually help with performance by making optimization opportunities more visible:

// ✅ Clear formatting reveals optimization opportunities
{div:{className:'user-list',
  children: () => {
    const users = getState('users.filtered', []); // Memoizable
    const selectedId = getState('ui.selectedUser'); // Simple state

    return users.map(user => ({
      div:{key:user.id, // Stable key for reconciliation
        className: selectedId === user.id ? 'user selected' : 'user',
        children:[
          {img:{src:user.avatar, alt:user.name}}, // Static content
          {span:{text:user.name}}, // Static content  
          {span:{                  // Dynamic content clearly separated
            text: () => getState(`users.${user.id}.status`, 'offline')
          }}
        ]
      }//div.user
    }));
  }
}}//div.user-list
Enter fullscreen mode Exit fullscreen mode

2. Avoiding Re-render Triggers

Proper formatting helps identify potential re-render issues:

// ✅ Clear separation of stable vs. dynamic props
{div:{className:'expensive-component', // Stable
  key: item.id,                        // Stable
  'data-testid': 'item-card',         // Stable
  style: () => ({                     // Dynamic - clearly marked
    backgroundColor: getState('theme.cardColor'),
    borderColor: getState('ui.focusedItem') === item.id ? 'blue' : 'gray'
  }),
  onClick: () => selectItem(item.id)  // Event handler - clearly separated
}}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Proper Object DOM formatting is not just about aesthetics—it's about creating maintainable, debuggable, and collaborative code. The Juris formatting philosophy provides a proven approach that:

  1. Makes structure immediately visible through end-bracket labeling
  2. Communicates intent through inline vs. new-line distinctions
  3. Reduces cognitive load by providing visual hierarchies
  4. Improves maintainability by making changes safer and easier
  5. Enhances team collaboration through consistent conventions

The key insight is that Object DOM formatting should serve the same purpose as HTML's visual structure—making the component hierarchy and behavior immediately clear to any developer reading the code.

By adopting these conventions, teams can harness the full power of Object DOM while maintaining the readability and maintainability that makes code sustainable over time.

Top comments (0)