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:
Take your React component. 🧑🎨
Wrap it with
r2wc
. 🛁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
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 {}
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"
]
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";
- 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";
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;
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>
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) : {};
}
}
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>
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
TypeScript Compatibility: If you see errors, try downgrading TypeScript to a compatible version.
Missing Styles: If your canvas looks broken, check
angular.json
to ensuretldraw.css
is added to the styles array.Prop Mismatches: Double-check the
props
object intldraw.js
to make sure attributes likeforceMobile
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! 🖐️🎉