Skip to content

Conversation

@fago
Copy link
Contributor

@fago fago commented Oct 29, 2025

Support for Explicit JSON API Format

NOTE: This summary was created with the help of AI, but thoroughly reviewed.

This PR adds support for a new, cleaner JSON format for custom elements with separated props and slots objects, while maintaining full backward compatibility with the legacy format.

🎯 Overview

Custom elements can now use a more structured JSON format that clearly separates component properties from slot content, making the API more maintainable and easier to work with.

📊 API Comparison

Before (Legacy Format)

{
  "element": "node-article-teaser",
  "title": "Article Title",
  "nid": 123,
  "default": "Content goes here",
  "sidebar": {
    "element": "drupal-block",
    "type": "search"
  }
}

Issues with legacy format:

  • Props and slots are mixed at the root level
  • No clear distinction between component properties and content slots
  • Harder to validate and maintain

After (Explicit Format)

{
  "element": "node-article-teaser",
  "props": {
    "title": "Article Title",
    "nid": 123
  },
  "slots": {
    "default": "Content goes here",
    "sidebar": {
      "element": "drupal-block",
      "props": { "type": "search" }
    }
  }
}

🔧 Configuration

New option added: customElementJsonFormat

export default defineNuxtConfig({
  drupalCe: {
    customElementJsonFormat: 'explicit', // 'explicit' (default) or 'legacy'
  }
})

Options:

  • 'explicit' (default, recommended): Modern format with separated props and slots

    • Automatically falls back to legacy format when different structure detected
    • Best for new projects
  • 'legacy': Legacy format with props and slots flattened at root level

    • Explicitly configure this for improved compatibility with older backends
    • Recommended for existing projects until Drupal backend is upgraded

⚠️ Compatibility & Migration

🔄 Backward Compatibility

This change is fully backward compatible:

  1. Default behavior includes automatic fallback

    • The 'explicit' format (default) automatically detects and handles legacy format
    • Existing projects continue to work without any changes
    • No immediate migration required
  2. Gradual migration path

    • Projects can continue using legacy format indefinitely
    • Upgrade to explicit format when ready

🎯 Recommended Configuration

For existing projects using older Drupal backends:

export default defineNuxtConfig({
  drupalCe: {
    customElementJsonFormat: 'legacy', // Explicitly configure for better compatibility
  }
})

For new projects or after Drupal upgrade:

export default defineNuxtConfig({
  drupalCe: {
    customElementJsonFormat: 'explicit', // Default - can be omitted
  }
})

🔗 Drupal Integration

Drupal Module: custom_elements 3.3.0

The explicit JSON format will ship with custom_elements 3.3.0 on the Drupal side. Related backend change: https://www.drupal.org/project/custom_elements/issues/3555044

Drupal Configuration:

  • Also configurable via Drupal settings
  • Existing installations: Default to 'legacy' format (no breaking changes)
  • New installations: Default to 'explicit' format (recommended)

📝 Changes Included

  • ✅ Added customElementJsonFormat configuration option
  • ✅ Support for explicit JSON format with props and slots separation
  • ✅ Automatic fallback to legacy format for backward compatibility
  • ✅ Updated TypeScript types to support both formats
  • ✅ Comprehensive test coverage for both formats
  • ✅ Documentation updates with examples and migration guide
  • ✅ Updated playground components to demonstrate both formats

📚 Documentation

Full documentation added to README.md including:

  • Configuration options
  • Before/After API examples
  • Compatibility notes

Copy link
Contributor Author

@fago fago left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see inline code comments

expect(wrapper.html()).not.toContain('display: contents')
})

it('renders only content prop when slot is empty', async () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

covered above already, drop

expect(wrapper.html()).toBeTruthy()
})

it('renders only slot when content prop is undefined', async () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

covered above already, drop

Copy link
Contributor Author

@fago fago left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see inline code comments

@fago fago merged commit af1b3b0 into 2.x Oct 31, 2025
1 check passed
@fago fago deleted the feature/support-explicit-api branch October 31, 2025 10:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants