Skip to content

Frontend Framework Integration

When to Use

Use JSON endpoints with React/Vue for fully decoupled sites. Use Drupal AJAX for simple enhancements. Choose one approach per feature — don't mix Drupal AJAX and framework AJAX for the same interaction.

Decision

If you need... Use... Why
Full decoupling JSON:API + custom AJAX endpoints React/Vue handle all rendering, Drupal is API only
Progressive decoupling Drupal AJAX + framework components Server renders initial page, JavaScript enhances
Simple enhancements Drupal AJAX only No framework overhead, faster initial load

Pattern

PHP JSON endpoint:

class ApiController extends ControllerBase {
  public function getData(Request $request) {
    $items = $this->loadItems();
    $data = array_map(fn($item) => [
      'id' => $item->id(),
      'title' => $item->label(),
      'body' => $item->get('body')->value,
    ], $items);

    return new JsonResponse(['data' => $data]);
  }
}

React component consuming endpoint:

// js/components/ItemList.jsx
function ItemList() {
  const [items, setItems] = useState([]);
  useEffect(() => {
    fetch('/my-module/api/items')
      .then(r => r.json())
      .then(data => setItems(data.data));
  }, []);
  return <ul>{items.map(i => <li key={i.id}>{i.title}</li>)}</ul>;
}

// Attach React component via Drupal.behaviors
(function (Drupal, React, ReactDOM) {
  Drupal.behaviors.reactItemList = {
    attach(context) {
      const el = document.getElementById('react-item-list');
      if (el && !el.hasAttribute('data-react-initialized')) {
        ReactDOM.render(<ItemList />, el);
        el.setAttribute('data-react-initialized', 'true');
      }
    }
  };
})(Drupal, React, ReactDOM);

Reference: core/modules/jsonapi/ (JSON:API module)

Common Mistakes

  • Wrong: Not protecting API endpoints → Right: Add authentication and CSRF protection for all data-changing endpoints
  • Wrong: Returning too much data → Right: Serialize only needed fields; avoid loading entire entity graphs
  • Wrong: Not handling CORS → Right: Configure CORS headers for cross-origin requests in services.yml
  • Wrong: Using both Drupal AJAX and framework AJAX for the same feature → Right: Choose one approach per interaction
  • Wrong: Rebuilding JSON:API for standard entities → Right: Use JSON:API module; don't reinvent a standards-compliant API

See Also