# Multi-Instance Spreadsheets

The `SpreadsheetMultiInstanceProvider` component allows you to render multiple spreadsheet instances within the same application while maintaining isolated state and preventing conflicts between instances.

## Overview

By default, each spreadsheet instance shares global context through `SpreadsheetProvider`. When you need to render multiple spreadsheets simultaneously (e.g., side-by-side comparison, multi-document interface), you need to wrap them in `SpreadsheetMultiInstanceProvider` to ensure proper isolation.

## Basic Usage

```tsx
import {
  SpreadsheetProvider,
  SpreadsheetMultiInstanceProvider,
  CanvasGrid,
} from "@rowsncolumns/spreadsheet";
import { useSpreadsheetState } from "@rowsncolumns/spreadsheet-state";

function MultiSpreadsheetApp() {
  return (
    <SpreadsheetMultiInstanceProvider>
      <SpreadsheetProvider>
        <SpreadsheetInstance instanceId="spreadsheet-1" />
      </SpreadsheetProvider>

      <SpreadsheetProvider>
        <SpreadsheetInstance instanceId="spreadsheet-2" />
      </SpreadsheetProvider>
    </SpreadsheetMultiInstanceProvider>
  );
}

function SpreadsheetInstance({ instanceId }: { instanceId: string }) {
  const {
    activeCell,
    activeSheetId,
    selections,
    // ... other state
  } = useSpreadsheetState({
    // configuration
  });

  return (
    <CanvasGrid
      instanceId={instanceId}
      sheetId={activeSheetId}
      activeCell={activeCell}
      selections={selections}
      // ... other props
    />
  );
}
```

## Instance ID

Each `CanvasGrid` instance should have a unique `instanceId` prop when rendered within `SpreadsheetMultiInstanceProvider`:

```tsx
<CanvasGrid
  instanceId="spreadsheet-a"  // Unique identifier
  sheetId={activeSheetId}
  // ... other props
/>
```

### Why Instance IDs Matter

Instance IDs ensure that:

* Keyboard events are routed to the correct spreadsheet
* Editor state is isolated between instances
* Context menus and dialogs appear in the correct location
* Formula evaluation doesn't cross instance boundaries

## Use Cases

### Side-by-Side Comparison

Compare two spreadsheets side by side:

```tsx
function SpreadsheetComparison() {
  return (
    <SpreadsheetMultiInstanceProvider>
      <div className="flex gap-4">
        <div className="flex-1">
          <h2>Version 1</h2>
          <SpreadsheetProvider>
            <SpreadsheetView instanceId="version-1" />
          </SpreadsheetProvider>
        </div>

        <div className="flex-1">
          <h2>Version 2</h2>
          <SpreadsheetProvider>
            <SpreadsheetView instanceId="version-2" />
          </SpreadsheetProvider>
        </div>
      </div>
    </SpreadsheetMultiInstanceProvider>
  );
}
```

### Multi-Document Interface

Create a tabbed or windowed interface with multiple spreadsheet documents:

```tsx
function MultiDocumentInterface() {
  const [documents] = useState([
    { id: "doc-1", name: "Budget 2024" },
    { id: "doc-2", name: "Sales Report" },
    { id: "doc-3", name: "Inventory" },
  ]);

  return (
    <SpreadsheetMultiInstanceProvider>
      {documents.map((doc) => (
        <SpreadsheetProvider key={doc.id}>
          <div className="document-window">
            <h3>{doc.name}</h3>
            <SpreadsheetView instanceId={doc.id} />
          </div>
        </SpreadsheetProvider>
      ))}
    </SpreadsheetMultiInstanceProvider>
  );
}
```

### Master-Detail View

Display a master spreadsheet with a detail view:

```tsx
function MasterDetailView() {
  const [selectedRow, setSelectedRow] = useState<number | null>(null);

  return (
    <SpreadsheetMultiInstanceProvider>
      <div className="grid grid-cols-2 gap-4">
        {/* Master spreadsheet */}
        <SpreadsheetProvider>
          <h2>Sales Overview</h2>
          <SpreadsheetView
            instanceId="master"
            onRowSelect={setSelectedRow}
          />
        </SpreadsheetProvider>

        {/* Detail spreadsheet */}
        {selectedRow && (
          <SpreadsheetProvider>
            <h2>Row Details</h2>
            <SpreadsheetView
              instanceId="detail"
              rowData={selectedRow}
            />
          </SpreadsheetProvider>
        )}
      </div>
    </SpreadsheetMultiInstanceProvider>
  );
}
```

## Complete Example

```tsx
import React, { useState } from "react";
import {
  SpreadsheetProvider,
  SpreadsheetMultiInstanceProvider,
  CanvasGrid,
  Sheet,
} from "@rowsncolumns/spreadsheet";
import {
  useSpreadsheetState,
  SheetData,
  CellData,
} from "@rowsncolumns/spreadsheet-state";

function App() {
  return (
    <SpreadsheetMultiInstanceProvider>
      <div className="flex gap-5 h-screen p-5">
        <div className="flex-1">
          <SpreadsheetProvider>
            <SpreadsheetA />
          </SpreadsheetProvider>
        </div>

        <div className="flex-1">
          <SpreadsheetProvider>
            <SpreadsheetB />
          </SpreadsheetProvider>
        </div>
      </div>
    </SpreadsheetMultiInstanceProvider>
  );
}

function SpreadsheetA() {
  const [sheets, setSheets] = useState<Sheet[]>([
    { sheetId: 1, rowCount: 100, columnCount: 26, title: "Sheet A" }
  ]);
  const [sheetData, setSheetData] = useState<SheetData<CellData>>({});

  const {
    activeCell,
    activeSheetId,
    selections,
    getCellData,
    onChangeActiveCell,
    onChangeSelections,
    onChange,
  } = useSpreadsheetState({
    sheets,
    sheetData,
    onChangeSheets: setSheets,
    onChangeSheetData: setSheetData,
  });

  return (
    <CanvasGrid
      instanceId="spreadsheet-a"
      sheetId={activeSheetId}
      activeCell={activeCell}
      selections={selections}
      getCellData={getCellData}
      onChangeActiveCell={onChangeActiveCell}
      onChangeSelections={onChangeSelections}
      onChange={onChange}
    />
  );
}

function SpreadsheetB() {
  // Similar implementation with different instance ID
  // ...

  return (
    <CanvasGrid
      instanceId="spreadsheet-b"
      // ... props
    />
  );
}
```

## Best Practices

1. **Always Use Unique Instance IDs**: Ensure each spreadsheet has a unique `instanceId` to prevent conflicts
2. **Wrap Each Instance**: Each spreadsheet should have its own `SpreadsheetProvider` wrapper
3. **Isolate State**: Use separate state management for each spreadsheet instance
4. **Performance Considerations**: Be mindful of rendering multiple large spreadsheets simultaneously - consider lazy loading or virtualization
5. **Memory Management**: Clean up instances when they're no longer needed to free up resources

## Limitations

* Each instance maintains its own calculation engine and state
* Cross-instance formulas are not supported (formulas cannot reference cells from other instances)
* Each instance requires separate data management

## Performance Tips

When rendering multiple instances:

```tsx
// Use React.memo to prevent unnecessary re-renders
const SpreadsheetInstance = React.memo(({ instanceId, data }) => {
  // ... implementation
});

// Lazy load instances that aren't immediately visible
const LazySpreadsheet = lazy(() => import('./SpreadsheetInstance'));

function MultiInstance() {
  return (
    <SpreadsheetMultiInstanceProvider>
      <Suspense fallback={<div>Loading...</div>}>
        <LazySpreadsheet instanceId="lazy-1" />
      </Suspense>
    </SpreadsheetMultiInstanceProvider>
  );
}
```

## Troubleshooting

### Keyboard Events Not Working

If keyboard events aren't working properly, ensure:

* Each `CanvasGrid` has a unique `instanceId`
* The `SpreadsheetMultiInstanceProvider` wraps all instances
* Only one spreadsheet has focus at a time

### State Conflicts

If you experience state conflicts between instances:

* Verify each instance has its own `SpreadsheetProvider`
* Check that state management is properly isolated
* Ensure instance IDs are unique and don't change during component lifecycle


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.rowsncolumns.app/configuration/features/multi-instance-spreadsheets.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
