Framework Comparison
This guide helps you understand the differences between React and Svelte when using Annota.
Quick Reference
Section titled “Quick Reference”Imports
Section titled “Imports”import { AnnotaProvider, AnnotaViewer, Annotator, AnnotationPopup,} from "annota";
import { useAnnotator, useAnnotations, useSelection, useTool,} from "annota";<script> import { AnnotaProvider, Viewer as AnnotaViewer, Annotator, Popup, } from "annota/svelte";
import { getAnnotator, annotations, selection, tool, } from "annota/svelte";</script>State Management
Section titled “State Management”Accessing the Annotator
Section titled “Accessing the Annotator”import { useAnnotator } from "annota";
function MyComponent() { const annotator = useAnnotator();
if (!annotator) return null;
return <div>Annotations: {annotator.state.store.all().length}</div>;}<script> import { getAnnotator } from "annota/svelte";
const getAnnotatorFn = getAnnotator(); const annotator = $derived(getAnnotatorFn());</script>
{#if annotator} <div>Annotations: {annotator.state.store.all().length}</div>{/if}Getting All Annotations
Section titled “Getting All Annotations”import { useAnnotations } from "annota";
function AnnotationList() { const annotations = useAnnotations();
return ( <ul> {annotations.map((ann) => ( <li key={ann.id}>{ann.shape.type}</li> ))} </ul> );}<script> import { annotations } from "annota/svelte";
const allAnnotations = annotations();</script>
<ul> {#each allAnnotations as ann (ann.id)} <li>{ann.shape.type}</li> {/each}</ul>Getting Selection
Section titled “Getting Selection”import { useSelection } from "annota";
function SelectionInfo() { const selection = useSelection();
return <p>Selected: {selection.length}</p>;}<script> import { selection } from "annota/svelte";
const selectedAnnotations = selection();</script>
<p>Selected: {selectedAnnotations.length}</p>Activating a Tool
Section titled “Activating a Tool”import { useTool } from "annota";import { RectangleTool } from "annota";
function ToolController({ viewer }) { const tool = new RectangleTool();
useTool({ viewer, handler: tool, enabled: true, });
return null;}<script> import { tool } from "annota/svelte"; import { RectangleTool } from "annota";
let viewer = $state(null);
const rectTool = $derived(new RectangleTool());
$effect(() => { if (!viewer) return;
tool({ viewer: () => viewer, handler: () => rectTool, enabled: () => true, }); });</script>Component Structure
Section titled “Component Structure”Provider Setup
Section titled “Provider Setup”import { AnnotaProvider, AnnotaViewer, Annotator } from "annota";
function App() { const [viewer, setViewer] = useState(null);
return ( <AnnotaProvider slideId="my-slide"> <AnnotaViewer onViewerReady={setViewer} /> <Annotator viewer={viewer} /> </AnnotaProvider> );}<script> import { AnnotaProvider, AnnotaViewer, Annotator } from "annota/svelte";
let viewer = $state(null);</script>
<AnnotaProvider slideId="my-slide"> <AnnotaViewer onViewerReady={(v) => viewer = v} /> {#if viewer} <Annotator {viewer} /> {/if}</AnnotaProvider>Syntax Differences
Section titled “Syntax Differences”Conditional Rendering
Section titled “Conditional Rendering”| React | Svelte |
|---|---|
{condition && <Component />} | {#if condition}<Component />{/if} |
{condition ? <A /> : <B />} | {#if condition}<A />{:else}<B />{/if} |
{!condition && <Component />} | {#if !condition}<Component />{/if} |
| React | Svelte |
|---|---|
{items.map(item => <div key={item.id}>{item.name}</div>)} | {#each items as item (item.id)}<div>{item.name}</div>{/each} |
Use key prop for keys | Use (item.id) for keys |
| React | Svelte |
|---|---|
const [state, setState] = useState() | let state = $state() |
const memo = useMemo(() => ..., [deps]) | const memo = $derived(...) |
useEffect(() => ..., [deps]) | $effect(() => ...) |
useCallback(fn, [deps]) | Function declarations (no deps) |
Common Patterns
Section titled “Common Patterns”Loading Annotations on Mount
Section titled “Loading Annotations on Mount”import { useAnnotator } from "annota";import { useEffect } from "react";
function LoadAnnotations({ slideId }) { const annotator = useAnnotator();
useEffect(() => { if (!annotator) return;
fetch(`/api/annotations/${slideId}`) .then(res => res.json()) .then(anns => annotator.addAnnotations(anns)); }, [annotator, slideId]);
return null;}<script> import { onMount } from "svelte"; import { getAnnotator } from "annota/svelte";
const { slideId } = $props(); const getAnnotatorFn = getAnnotator(); const annotator = $derived(getAnnotatorFn());
onMount(() => { if (!$annotator) return;
fetch(`/api/annotations/${slideId}`) .then(res => res.json()) .then(anns => $annotator.addAnnotations(anns)); });</script>Custom Styling Function
Section titled “Custom Styling Function”<Annotator viewer={viewer} style={(annotation) => ({ fill: annotation.properties?.type === "tumor" ? "#FF0000" : "#00FF00", fillOpacity: 0.3, })}/><script> function getStyle(annotation) { return { fill: annotation.properties?.type === "tumor" ? "#FF0000" : "#00FF00", fillOpacity: 0.3, }; }</script>
<Annotator {viewer} style={getStyle} />Migration Guide
Section titled “Migration Guide”From React to Svelte
Section titled “From React to Svelte”-
Replace hooks with stores:
useAnnotator()→getAnnotator()()with$deriveduseAnnotations()→annotations()useSelection()→selection()
-
Update state syntax:
useState()→$state()useMemo()→$derived()useEffect()→$effect()
-
Change JSX to Svelte syntax:
className→classstyle={{...}}→style="..."onClick={...}→onclick={...}
-
Update imports:
from "annota"→from "annota/svelte"
From Svelte to React
Section titled “From Svelte to React”-
Replace stores with hooks:
annotations()→useAnnotations()selection()→useSelection()getAnnotator()()→useAnnotator()
-
Update state syntax:
$state()→useState()$derived()→useMemo()$effect()→useEffect()
-
Change Svelte syntax to JSX:
class→classNameonclick→onClick{#if}→{&&}or ternary
-
Update imports:
from "annota/svelte"→from "annota"