DEV Community

Cover image for 🎨 Mastering Angular-React Integration: How to Use tldraw Without Losing Your Mind!
Balaji Sasikumar
Balaji Sasikumar

Posted on

🎨 Mastering Angular-React Integration: How to Use tldraw Without Losing Your Mind!

Introduction

If you’re an Angular dev eyeing the React world, you might feel like a cat walking into a dog park. tldraw—the cool kid on the React block—makes it seem worth the risk. But how do you get them to play nicely together? By using web components, the ultimate middleman that lets Angular and React shake hands instead of throwing shade. 🚀


What are Web Components?

Imagine a magical HTML element that doesn’t care who made it—it just works. That’s a web component for you! It's like the Switzerland of the web frameworks, neutral and ready to mediate.

Key Features:

  • Custom Elements: Make up your own tags like <awesome-button>.
  • Shadow DOM: Keeps your styles from messing with everyone else’s (no sibling drama here!).
  • HTML Templates: Build it once, reuse it everywhere (yes, like Legos).

What is r2wc?

Think of r2wc as the translator between React and the rest of the web. It wraps your React components in a cozy custom element that even Angular can understand. 😎


How it Works:

  1. Take your React component. 🧑‍🎨
  2. Wrap it with r2wc. 🛁
  3. Register it as a custom element with a snazzy name like <tl-draw>. 🏷️

Step-by-Step Guide

Step 1: Install the Required Stuff

Get the cool toys with:

npm install @r2wc/react-to-web-component @tldraw/tldraw react react-dom
Enter fullscreen mode Exit fullscreen mode

Step 2: Let Angular Know About Web Components

Add this to your Angular module, so Angular doesn’t freak out about your new custom elements:

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  bootstrap: [AppComponent],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

Step 3: Add tldraw Styles

You can’t draw without style, right? Add tldraw's styles to your Angular app.

Open angular.json and include the following in the styles array:

"styles": [
  "src/global.scss",
  "node_modules/tldraw/tldraw.css"
]
Enter fullscreen mode Exit fullscreen mode

Step 4: Importing tldraw Based on Angular Version

  • For Angular 15 and Above:
import r2wc from "@r2wc/react-to-web-component";
import { Tldraw, getSnapshot } from "@tldraw/tldraw";
Enter fullscreen mode Exit fullscreen mode
  • For Angular Below 15:
import r2wc from "../../node_modules/@r2wc/react-to-web-component/dist/react-to-web-component.js";
import { Tldraw, getSnapshot } from "../../node_modules/tldraw/dist-esm/index.mjs";
Enter fullscreen mode Exit fullscreen mode

Because Angular’s TypeScript isn’t quite ready to hang with tldraw. 🙃. This workaround is necessary because tldraw uses TypeScript features that older Angular versions don’t fully support.


Step 5: Create tldraw.js

Create a file named tldraw.js to convert the tldraw React component into a web component.

Here’s the magic potion that converts tldraw into a web component:

import r2wc from "@r2wc/react-to-web-component";
import { Tldraw, getSnapshot } from "@tldraw/tldraw";

const TldrawComponent = r2wc(Tldraw, {
  props: {
    forceMobile: "boolean",
    snapshot: "json",
    onMount: "function",
  },
});

customElements.define("tl-draw", TldrawComponent);

export const getSnapshot1 = getSnapshot;
Enter fullscreen mode Exit fullscreen mode

This wraps the tldraw component and defines it as a custom element named .


Step 6: Use the Web Component in Angular

Here’s how you can use <tl-draw> in your Angular app.

HTML (app.component.html):

<div style="width: 100vw; height: 95vh">
  <button
    (click)="handleSaveChanges()"
    [ngStyle]="{
      position: 'absolute',
      top: '44px',
      right: '0.5em',
      padding: '8px 16px',
      zIndex: 100,
      backgroundColor: hasUnsavedChanges ? '#007bff' : '#ccc',
      cursor: hasUnsavedChanges ? 'pointer' : 'not-allowed',
      opacity: hasUnsavedChanges ? 1 : 0.6
    }"
  >
    Save
  </button>
  <tl-draw
    [forceMobile]="true"
    [snapshot]="snapshot"
    [onMount]="onMountEvent"
  ></tl-draw>
</div>
Enter fullscreen mode Exit fullscreen mode

TypeScript (app.component.ts):

import { Component, OnInit } from '@angular/core';
import { getSnapshot1 } from './path-to-tldraw.js';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {
  hasUnsavedChanges = false;
  snapshot: any;
  editor: any;

  onMountEvent = (editor: any) => {
    this.editor = editor;
    editor.store.listen(this.handleChangeEvent, { source: 'user', scope: 'all' });
  };

  handleChangeEvent = (change: any) => {
    if (
      Object.keys(change.changes.added).length ||
      Object.keys(change.changes.updated).length ||
      Object.keys(change.changes.removed).length
    ) {
      this.hasUnsavedChanges = true;
    }
  };

  handleSaveChanges = () => {
    const snapshot = getSnapshot1(this.editor.store);
    console.log('Snapshot saved:', snapshot);
    this.hasUnsavedChanges = false;
    localStorage.setItem('drawingSnapshot', JSON.stringify(snapshot));
  };

  ngOnInit() {
    const savedSnapshot = localStorage.getItem('drawingSnapshot');
    this.snapshot = savedSnapshot ? JSON.parse(savedSnapshot) : {};
  }
}
Enter fullscreen mode Exit fullscreen mode

Now, you’re all set to use tldraw in your Angular app! 🎉


Key Takeaways

  • Props Mapping: React props become Angular-friendly attributes via r2wc. For example:
<tl-draw
    [forceMobile]="true"
    [snapshot]="snapshot"
    [onMount]="onMountEvent"
></tl-draw>
Enter fullscreen mode Exit fullscreen mode
  • Event Handling: Use Angular bindings to handle events like [onMount]="onMountEvent".
  • Snapshots FTW: Save and restore drawing state using getSnapshot.

You’ve successfully bridged the React-Angular divide! 🎉


Common Gotchas

  1. TypeScript Compatibility: If you see errors, try downgrading TypeScript to a compatible version.

  2. Missing Styles: If your canvas looks broken, check angular.json to ensure tldraw.css is added to the styles array.

  3. Prop Mismatches: Double-check the props object in tldraw.js to make sure attributes like forceMobile are correctly exposed.


Conclusion

By the time you’re done, your Angular app will be flexing tldraw like it was born to do it. Who said React and Angular can’t get along? With a little help from r2wc, you’ve just made it happen. Go on, give yourself a high five! 🖐️🎉

Top comments (0)