> ## Documentation Index
> Fetch the complete documentation index at: https://superdoc-caio-pizzol-docs-ai-core-preset.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Image extension

export const SourceCodeLink = ({extension, path}) => {
  const githubPath = path || `packages/super-editor/src/editors/v1/extensions/${extension.toLowerCase()}`;
  const githubUrl = `https://github.com/superdoc-dev/superdoc/tree/main/${githubPath}`;
  return <div>
      <p>
        <a href={githubUrl} target="_blank" rel="noopener noreferrer">
          View on GitHub →
        </a>
      </p>
    </div>;
};

export const SuperDocEditor = ({html = '<p>Start editing...</p>', height = '400px', maxHeight = '400px', onReady = null, showExport = true, customButtons = null}) => {
  const [ready, setReady] = useState(false);
  const editorRef = useRef(null);
  const containerIdRef = useRef(`editor-${Math.random().toString(36).substr(2, 9)}`);
  const DEV_DIST_URL = 'http://localhost:9094/dist';
  const UNPKG_DIST_URL = 'https://unpkg.com/superdoc@latest/dist';
  const getBaseUrl = async () => {
    const isDev = typeof window !== 'undefined' && window.location.hostname === 'localhost';
    if (isDev) {
      try {
        const res = await fetch(`${DEV_DIST_URL}/superdoc.min.js`, {
          method: 'HEAD'
        });
        if (res.ok) {
          console.info('[SuperDoc Docs] Using local build from', DEV_DIST_URL);
          return DEV_DIST_URL;
        }
        console.warn('[SuperDoc Docs] Local dev server returned', res.status, '- falling back to unpkg');
      } catch (err) {
        console.warn('[SuperDoc Docs] Local dev server not reachable: falling back to unpkg.', 'Run `pnpm dev:docs` from the repo root to use your local build.', err.message);
      }
    }
    return UNPKG_DIST_URL;
  };
  const ensureStyle = baseUrl => {
    const styleHref = `${baseUrl}/style.css`;
    if (document.querySelector(`link[href="${styleHref}"]`)) return;
    const link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href = styleHref;
    document.head.appendChild(link);
  };
  const loadSuperDoc = baseUrl => {
    if (window.SuperDoc) return Promise.resolve();
    const scriptSrc = `${baseUrl}/superdoc.min.js`;
    const existingScript = document.querySelector(`script[src="${scriptSrc}"]`);
    if (existingScript) {
      if (window.SuperDoc) return Promise.resolve();
      return new Promise((resolve, reject) => {
        existingScript.addEventListener('load', resolve, {
          once: true
        });
        existingScript.addEventListener('error', reject, {
          once: true
        });
      });
    }
    return new Promise((resolve, reject) => {
      const script = document.createElement('script');
      script.src = scriptSrc;
      script.onload = resolve;
      script.onerror = reject;
      document.body.appendChild(script);
    });
  };
  const initEditor = () => {
    setTimeout(() => {
      if (!window.SuperDoc) return;
      if (!document.getElementById(containerIdRef.current)) return;
      if (editorRef.current) return;
      editorRef.current = new window.SuperDoc({
        selector: `#${containerIdRef.current}`,
        html,
        rulers: true,
        contained: true,
        onReady: () => {
          setReady(true);
          if (onReady) onReady(editorRef.current);
        }
      });
    }, 100);
  };
  useEffect(() => {
    let cancelled = false;
    const boot = async () => {
      try {
        const baseUrl = await getBaseUrl();
        ensureStyle(baseUrl);
        await loadSuperDoc(baseUrl);
        if (!cancelled) initEditor();
      } catch (error) {
        console.error('Failed to boot SuperDoc:', error);
      }
    };
    boot();
    return () => {
      cancelled = true;
      editorRef.current?.destroy?.();
      editorRef.current = null;
    };
  }, []);
  const exportDocx = () => {
    if (editorRef.current?.export) {
      editorRef.current.export();
    }
  };
  return <div className="border rounded-lg bg-white overflow-hidden">
      {ready && (showExport || customButtons) && <div className="px-3 py-2 bg-gray-50 border-b">
          {customButtons && <div className="space-y-1 mb-2">
              {customButtons.map((row, rowIndex) => <div key={rowIndex} className="flex gap-1">
                  {row.map((btn, i) => <button key={i} onClick={() => btn.onClick(editorRef.current)} className={btn.className || 'flex-1 px-2 py-1 bg-gray-100 text-gray-700 text-xs rounded hover:bg-gray-200'}>
                      {btn.label}
                    </button>)}
                </div>)}
            </div>}
          {showExport && <div className="text-right">
              <button onClick={exportDocx} className="px-3 py-1 bg-blue-500 text-white text-xs rounded hover:bg-blue-600">
                Export DOCX
              </button>
            </div>}
        </div>}
      <div id={containerIdRef.current} style={{
    height,
    maxHeight,
    paddingLeft: '5px'
  }} />
      <style jsx>{`
        #${containerIdRef.current} .superdoc__layers {
          max-width: 660px !important;
        }
        #${containerIdRef.current} .super-editor {
          max-width: 100% !important;
          width: 100% !important;
          color: #000;
        }
        #${containerIdRef.current} .editor-element {
          width: 100% !important;
          min-width: unset !important;
          transform: none !important;
        }
        #${containerIdRef.current} .editor-element {
          h1,
          h2,
          h3,
          h4,
          h5,
          strong {
            color: #000;
          }
        }
      `}</style>
    </div>;
};

Insert and manage images with perfect Word compatibility.

Supports URLs, base64 data, and maintains positioning for Word export.

<SuperDocEditor
  html={`<p>Images can be inserted inline with text.</p><p><img src="/public/images/extensions/image-landscape.png" alt="Sample landscape" style="width: 300px; height: auto;"></p><p>Images automatically scale and position correctly in both the editor and Word export.</p>`}
  height="350px"
  customButtons={[
[
  {
    label: 'Add from URL',
    onClick: (superdoc) => {
      const editor = superdoc?.activeEditor || superdoc?.editor
      if (!editor?.commands) return
      editor.commands.setImage({
        src: 'https://picsum.photos/id/237/200/150',
        alt: 'External image from URL',
        size: { width: 200 }
      })
    }
  },
  {
    label: 'Add Local Image',
    onClick: (superdoc) => {
      const editor = superdoc?.activeEditor || superdoc?.editor
      if (!editor?.commands) return
      editor.commands.setImage({
        src: '/public/images/extensions/image-chart.png',
        alt: 'Chart visualization',
        size: { width: 250 }
      })
    }
  },
  {
    label: 'Add with Padding',
    onClick: (superdoc) => {
      const editor = superdoc?.activeEditor || superdoc?.editor
      if (!editor?.commands) return
      editor.commands.setImage({
        src: '/public/images/extensions/image-icon.png',
        alt: 'Document icon',
        size: { width: 100 },
        padding: { left: 20, right: 20, top: 10, bottom: 10 }
      })
    }
  }
]
]}
/>

## OOXML Structure

```xml theme={null}
<w:drawing>
  <wp:inline distT="0" distB="0" distL="0" distR="0">
    <wp:extent cx="5715000" cy="3810000"/>
    <wp:docPr id="1" name="Picture 1"/>
    <a:graphic>
      <a:graphicData>
        <pic:pic>
          <pic:blipFill>
            <a:blip r:embed="rId7"/>
          </pic:blipFill>
        </pic:pic>
      </a:graphicData>
    </a:graphic>
  </wp:inline>
</w:drawing>
```

## Use case

* **Document illustrations** - Add diagrams, charts, and screenshots
* **Product documentation** - Include product images and UI screenshots
* **Reports** - Embed data visualizations and infographics
* **Branding** - Insert logos and company graphics
* **Base64 support** - Embed images directly without external files

## Options

Configure the extension behavior:

<ParamField path="allowBase64" type="boolean" default="true">
  Allow base64 encoded images
</ParamField>

<ParamField path="htmlAttributes" type="Object">
  Default HTML attributes for image elements
</ParamField>

## Attributes

Node attributes that can be set and retrieved:

<ParamField path="src" type="string">
  Image source URL or path
</ParamField>

<ParamField path="alt" type="string" default="Uploaded picture">
  Alternative text for accessibility
</ParamField>

<ParamField path="title" type="string">
  Image title/tooltip text
</ParamField>

<ParamField path="size" type="Object">
  Image dimensions
</ParamField>

<ParamField path="size.width" type="number">
  Width in pixels
</ParamField>

<ParamField path="size.height" type="number">
  Height in pixels
</ParamField>

<ParamField path="padding" type="Object">
  Image padding/margins
</ParamField>

<ParamField path="padding.left" type="number">
  Left padding in pixels
</ParamField>

<ParamField path="padding.top" type="number">
  Top padding in pixels
</ParamField>

<ParamField path="padding.bottom" type="number">
  Bottom padding in pixels
</ParamField>

<ParamField path="padding.right" type="number">
  Right padding in pixels
</ParamField>

<ParamField path="marginOffset" type="Object">
  Margin offset for anchored images
</ParamField>

<ParamField path="marginOffset.horizontal" type="number">
  Left/right margin offset
</ParamField>

<ParamField path="marginOffset.top" type="number">
  Top margin offset
</ParamField>

<ParamField path="style" type="string">
  Custom inline CSS styles
</ParamField>

<ParamField path="wrap" type="Object" default="{ type: 'Inline' }">
  Text wrapping configuration. The `type` property controls wrapping mode (e.g., `'Inline'`, `'Square'`, `'Tight'`, `'TopAndBottom'`, `'None'`).
</ParamField>

<ParamField path="transformData" type="Object" default="{}">
  Transform data for rotation, flips, and size extension. Supports `rotation` (degrees), `flipH` (horizontal flip), `flipV` (vertical flip), and `sizeExtension` properties.
</ParamField>

## Commands

### `setImage`

Insert an image at the current position

<Note>
  Supports URLs, relative paths, and base64 data URIs
</Note>

**Example:**

<CodeGroup>
  ```javascript Usage theme={null}
  editor.commands.setImage({ src: 'https://example.com/image.jpg' })
  editor.commands.setImage({
    src: 'data:image/png;base64,...',
    alt: 'Company logo',
    size: { width: 200 }
  })
  ```

  ```javascript Full Example theme={null}
  import { SuperDoc } from 'superdoc';
  import 'superdoc/style.css';

  const superdoc = new SuperDoc({
    selector: '#editor',
    document: yourFile,
    onReady: (superdoc) => {
      const editor = superdoc.activeEditor;
      editor.commands.setImage({ src: 'https://example.com/image.jpg' })
      editor.commands.setImage({
        src: 'data:image/png;base64,...',
        alt: 'Company logo',
        size: { width: 200 }
      })
    },
  });
  ```
</CodeGroup>

**Parameters:**

<ParamField path="options" type="ImageInsertOptions" required>
  Image insertion options
</ParamField>

### `setWrapping`

Set the wrapping mode and attributes for the selected image

**Example:**

<CodeGroup>
  ```javascript Usage theme={null}
  // No wrapping, behind document
  editor.commands.setWrapping({ type: 'None', attrs: {behindDoc: true} })

  // Square wrapping on both sides with distances
  editor.commands.setWrapping({
    type: 'Square',
    attrs: {
      wrapText: 'bothSides',
      distTop: 10,
      distBottom: 10,
      distLeft: 10,
      distRight: 10
    }
  })

  // Tight wrapping with polygon
  editor.commands.setWrapping({
    type: 'Tight',
    attrs: {
      polygon: [[0, 0], [100, 0], [100, 100], [0, 100]]
    }
  })

  // Top and bottom wrapping
  editor.commands.setWrapping({
    type: 'TopAndBottom',
    attrs: {
      distTop: 15,
      distBottom: 15
    }
  })
  ```

  ```javascript Full Example theme={null}
  import { SuperDoc } from 'superdoc';
  import 'superdoc/style.css';

  const superdoc = new SuperDoc({
    selector: '#editor',
    document: yourFile,
    onReady: (superdoc) => {
      const editor = superdoc.activeEditor;
      // No wrapping, behind document
      editor.commands.setWrapping({ type: 'None', attrs: {behindDoc: true} })

      // Square wrapping on both sides with distances
      editor.commands.setWrapping({
        type: 'Square',
        attrs: {
          wrapText: 'bothSides',
          distTop: 10,
          distBottom: 10,
          distLeft: 10,
          distRight: 10
        }
      })

      // Tight wrapping with polygon
      editor.commands.setWrapping({
        type: 'Tight',
        attrs: {
          polygon: [[0, 0], [100, 0], [100, 100], [0, 100]]
        }
      })

      // Top and bottom wrapping
      editor.commands.setWrapping({
        type: 'TopAndBottom',
        attrs: {
          distTop: 15,
          distBottom: 15
        }
      })
    },
  });
  ```
</CodeGroup>

**Parameters:**

<ParamField path="options" type="Object" required>
  Wrapping options
</ParamField>

## Types

### `ImageInsertOptions`

Options for inserting an image

<Expandable title="Properties">
  <ResponseField name="src" type="string" required>
    Image source URL or data URI
  </ResponseField>

  <ResponseField name="alt" type="string">
    Alternative text
  </ResponseField>

  <ResponseField name="title" type="string">
    Image title
  </ResponseField>

  <ResponseField name="size" type="Object">
    Image dimensions
  </ResponseField>

  <ResponseField name="size.width" type="number">
    Width in pixels
  </ResponseField>

  <ResponseField name="size.height" type="number">
    Height in pixels
  </ResponseField>
</Expandable>

## Source code

<SourceCodeLink path="packages/super-editor/src/editors/v1/extensions/image/image.js" />
