# Using it in a framework

> Wrap WellRenderer in a Vue or React component that renders on the client only, redraws when the data changes, follows the container width and cleans up.

The renderer is framework-free: it needs an `<svg>` element in the page and a `Well`. In a component framework the pattern is always the same:

1. Render an empty `<svg>` with a unique id.
2. After mount, import the package, create the renderer, call `prepareSvg()` and `draw()`.
3. Redraw when the well changes; rebuild when the size or theme changes.
4. Never run it during server-side rendering.

## Vue 3

```vue [WellProfile.vue]
<script setup lang="ts">
import type { Well } from '@welldot/core';
import type { WellRenderer } from '@welldot/render';
import { onMounted, ref, useId, watch } from 'vue';

const props = defineProps<{ well: Well; height?: number }>();

const id = `well-${useId()}`;
const container = ref<HTMLElement | null>(null);
let renderer: WellRenderer | null = null;

async function build() {
  const { WellRenderer, INTERACTIVE_RENDER_CONFIG, applyRenderLocale } =
    await import('@welldot/render');
  const margins = { top: 24, right: 16, bottom: 20, left: 48 };
  const width =
    (container.value?.clientWidth ?? 400) - margins.left - margins.right;
  renderer = new WellRenderer(
    [{ selector: `#${id}`, width, height: props.height ?? 600, margins }],
    {
      locale: 'en',
      renderConfig: {
        ...applyRenderLocale(INTERACTIVE_RENDER_CONFIG, 'en'),
        zoom: false,
        pan: false,
      },
      onError: e => console.error(e),
    },
  );
  await renderer.prepareSvg();
  renderer.draw(props.well);
}

onMounted(build);
watch(
  () => props.well,
  well => renderer?.draw(well),
  { deep: true },
);
</script>

<template>
  <div ref="container">
    <svg :id="id" />
  </div>
</template>
```

`onMounted` never runs on the server, so this component is safe in Nuxt as it is. The dynamic `import()` keeps D3 out of the server bundle. In Nuxt, wrapping it in `<ClientOnly>` also avoids a hydration warning for the empty SVG.

## React

```tsx [WellProfile.tsx]
import type { Well } from '@welldot/core';
import type { WellRenderer } from '@welldot/render';
import { useEffect, useId, useRef } from 'react';

export function WellProfile({
  well,
  height = 600,
}: {
  well: Well;
  height?: number;
}) {
  const id = `well-${useId().replace(/:/g, '')}`;
  const container = useRef<HTMLDivElement>(null);
  const renderer = useRef<WellRenderer | null>(null);

  useEffect(() => {
    let cancelled = false;
    (async () => {
      const { WellRenderer, INTERACTIVE_RENDER_CONFIG, applyRenderLocale } =
        await import('@welldot/render');
      if (cancelled) return;
      const margins = { top: 24, right: 16, bottom: 20, left: 48 };
      const width =
        (container.current?.clientWidth ?? 400) - margins.left - margins.right;
      const r = new WellRenderer(
        [{ selector: `#${id}`, width, height, margins }],
        {
          locale: 'en',
          renderConfig: {
            ...applyRenderLocale(INTERACTIVE_RENDER_CONFIG, 'en'),
            zoom: false,
            pan: false,
          },
        },
      );
      await r.prepareSvg();
      renderer.current = r;
      r.draw(well);
    })();
    return () => {
      cancelled = true;
      renderer.current?.clear();
    };
  }, [id, height]);

  useEffect(() => {
    renderer.current?.draw(well);
  }, [well]);

  return (
    <div ref={container}>
      <svg id={id} />
    </div>
  );
}
```

In Next.js, mark the file `'use client'`. React's `useId` returns ids with colons, which are not valid in a CSS selector, hence the `replace`.

## Resizing and themes

The renderer draws at the size it was created with. To follow the container, observe it and rebuild after a short pause; to follow a dark mode switch, rebuild with the other theme ([Theming](/render/guides/theming#dark-mode)). Rebuilding is cheap: create the new renderer, `prepareSvg()`, `draw()`.

## Validation first

Parse with `parseWell` before handing data to the renderer, and show the errors when it fails, as the [live previews](/contributing/components) on this site do. The renderer expects a valid `Well`; it reports drawing problems through `onError` but does not validate.
