> For the complete documentation index, see [llms.txt](https://docs.rowsncolumns.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rowsncolumns.app/configuration/api/hooks.md).

# Hooks

The spreadsheet provides several utility hooks for common operations beyond the main `useSpreadsheetState` hook.

## useNavigateToSheetRange

Navigate to a specific cell or range in a sheet, optionally with a visual flash effect.

### Basic Usage

```tsx
import { useNavigateToSheetRange } from "@rowsncolumns/spreadsheet";
import { useSpreadsheetState } from "@rowsncolumns/spreadsheet-state";

function MySpreadsheet() {
  const navigateToSheetRange = useNavigateToSheetRange();

  const handleGoToRange = () => {
    navigateToSheetRange?.({
      sheetId: 2,
      startRowIndex: 10,
      endRowIndex: 15,
      startColumnIndex: 5,
      endColumnIndex: 8,
    });
  };

  return (
    <button onClick={handleGoToRange}>
      Go to Sheet 2, Range F11:I16
    </button>
  );
}
```

### Parameters

```typescript
navigateToSheetRange(
  sheetRange: SheetRange,     // The range to navigate to
  {
    enableFlash?: boolean,       // Show flash effect (default: true)
    flashColor?: Color,          // Flash color (default: "#ffcc00")
    flashDuration?: number       // Flash duration in ms (default: 1500)
  }
)
```

### Features

* **Sheet switching**: Automatically switches to the target sheet
* **Cell positioning**: Sets active cell to the top-left of the range
* **Scrolling**: Scrolls the range into view
* **Visual feedback**: Optional flash effect to highlight the range

### Example with Custom Flash

```tsx
const navigateToSheetRange = useNavigateToSheetRange();

// Navigate with red flash for 2 seconds
navigateToSheetRange?.(
  {
    sheetId: 1,
    startRowIndex: 5,
    endRowIndex: 10,
    startColumnIndex: 3,
    endColumnIndex: 6,
  },
  {
    enableFlash: true,      // Enable flash
    flashColor: "#ff0000", // Red color
    flashDuration: 2000       // 2 seconds
  }  
);
```

### Use Cases

* **Jump to errors**: Navigate to cells with validation errors
* **Go to formulas**: Jump to cells referenced in formulas
* **Search results**: Navigate to search result cells
* **Links**: Implement cell links to other sheet locations
* **Named ranges**: Jump to named range locations

## useLoadingIndicator

Display a loading indicator during async operations.

### Basic Usage

```tsx
import { useLoadingIndicator, LoadingIndicator } from "@rowsncolumns/spreadsheet";

function MySpreadsheet() {
  const [showLoader, hideLoader] = useLoadingIndicator();

  const handleAsyncOperation = async () => {
    showLoader();
    try {
      await someAsyncOperation();
    } finally {
      hideLoader();
    }
  };

  return (
    <>
      <button onClick={handleAsyncOperation}>
        Load Data
      </button>
      <CanvasGrid />
      <LoadingIndicator />
    </>
  );
}
```

### API

The hook returns a tuple:

```typescript
const [showLoader, hideLoader] = useLoadingIndicator();
```

* `showLoader()`: Shows the loading indicator
* `hideLoader()`: Hides the loading indicator

### Example with Multiple Operations

```tsx
function SpreadsheetWithAsyncOps() {
  const [showLoader, hideLoader] = useLoadingIndicator();

  const loadData = async () => {
    showLoader();
    try {
      const data = await fetchSpreadsheetData();
      setSheetData(data);
    } catch (error) {
      console.error("Failed to load data:", error);
    } finally {
      hideLoader();
    }
  };

  const saveData = async () => {
    showLoader();
    try {
      await saveSpreadsheetData(sheetData);
    } finally {
      hideLoader();
    }
  };

  return (
    <>
      <button onClick={loadData}>Load</button>
      <button onClick={saveData}>Save</button>
      <CanvasGrid />
      <LoadingIndicator />
    </>
  );
}
```

### Component

The `LoadingIndicator` component must be rendered in your app (typically at the root level):

```tsx
<SpreadsheetProvider>
  <Toolbar />
  <CanvasGrid />
  <LoadingIndicator />  {/* Required for the hook to work */}
</SpreadsheetProvider>
```

### Use Cases

* **Data loading**: Show loader while fetching data from server
* **File import**: Display during Excel/CSV import operations
* **Calculations**: Show during long-running calculations
* **Export operations**: Display while generating exports

## useSpreadsheetApi

Access the imperative API for programmatic control of the spreadsheet.

### Basic Usage

```tsx
import { useSpreadsheetApi } from "@rowsncolumns/spreadsheet";

function MyComponent() {
  const api = useSpreadsheetApi();

  const updateCell = () => {
    api?.getActiveSheet()
      ?.getRange({ rowIndex: 1, columnIndex: 1 })
      .setValue("Hello World")
      .setFormat("backgroundColor", "#ffcc00");
  };

  return <button onClick={updateCell}>Update A1</button>;
}
```

See [Imperative Spreadsheet API](/getting-started/imperative-spreadsheet-api.md) for complete documentation.

## Complete Example

```tsx
import React, { useState } from "react";
import {
  SpreadsheetProvider,
  CanvasGrid,
  LoadingIndicator,
  useLoadingIndicator,
  useNavigateToSheetRange,
  useSpreadsheetApi,
} from "@rowsncolumns/spreadsheet";
import {
  useSpreadsheetState,
  type SheetData,
} from "@rowsncolumns/spreadsheet-state";

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

  return (
    <SpreadsheetProvider>
      <SpreadsheetControls
        sheets={sheets}
        sheetData={sheetData}
        onChangeSheets={setSheets}
        onChangeSheetData={setSheetData}
      />
    </SpreadsheetProvider>
  );
}

function SpreadsheetControls({ sheets, sheetData, onChangeSheets, onChangeSheetData }) {
  const [showLoader, hideLoader] = useLoadingIndicator();
  const navigateToSheetRange = useNavigateToSheetRange();
  const api = useSpreadsheetApi();

  const {
    activeCell,
    activeSheetId,
    selections,
    getCellData,
    onChangeActiveCell,
    onChangeSelections,
    onChangeActiveSheet,
  } = useSpreadsheetState({
    sheets,
    sheetData,
    onChangeSheets,
    onChangeSheetData,
  });

  const findAndNavigate = async () => {
    showLoader();
    try {
      // Simulate search operation
      await new Promise(resolve => setTimeout(resolve, 1000));
      
      // Navigate to found cell
      navigateToSheetRange?.({
        sheetId: 2,
        startRowIndex: 15,
        endRowIndex: 15,
        startColumnIndex: 5,
        endColumnIndex: 5,
      });
    } finally {
      hideLoader();
    }
  };

  const updateCellProgrammatically = () => {
    api?.getActiveSheet()
      ?.getRange({ rowIndex: 1, columnIndex: 1 })
      .setValue("Updated via API");
  };

  return (
    <>
      <div className="toolbar">
        <button onClick={findAndNavigate}>
          Find and Navigate
        </button>
        <button onClick={updateCellProgrammatically}>
          Update A1
        </button>
      </div>

      <CanvasGrid
        sheetId={activeSheetId}
        activeCell={activeCell}
        selections={selections}
        getCellData={getCellData}
        onChangeActiveCell={onChangeActiveCell}
        onChangeSelections={onChangeSelections}
        onChangeActiveSheet={onChangeActiveSheet}
      />

      <LoadingIndicator />
    </>
  );
}

export default SpreadsheetWithHooks;
```

## Hook Dependencies

### useNavigateToSheetRange

Requires `SpreadsheetProvider` context:

```tsx
<SpreadsheetProvider>
  {/* Component using useNavigateToSheetRange */}
</SpreadsheetProvider>
```

### useLoadingIndicator

Requires `LoadingIndicator` component to be rendered:

```tsx
<SpreadsheetProvider>
  <YourComponents />
  <LoadingIndicator />  {/* Required */}
</SpreadsheetProvider>
```

### useSpreadsheetApi

Requires `SpreadsheetProvider` and active spreadsheet state:

```tsx
<SpreadsheetProvider>
  {/* Component using useSpreadsheetApi */}
</SpreadsheetProvider>
```

## Best Practices

### useNavigateToSheetRange

1. **User feedback**: Always provide visual feedback when navigating (use flash effect)
2. **Bounds checking**: Ensure the range exists before navigating
3. **Sheet existence**: Verify the target sheet exists

### useLoadingIndicator

1. **Always hide**: Use try-finally to ensure hideLoader is called
2. **Error handling**: Show errors to users if operations fail
3. **Timeout**: Consider adding timeouts for long operations
4. **Multiple operations**: Use separate show/hide pairs for different operations

### useSpreadsheetApi

1. **Null checking**: Always use optional chaining (`api?.`)
2. **State management**: Prefer declarative state over imperative API when possible
3. **Batch operations**: Use batch methods for multiple changes

## TypeScript Support

All hooks are fully typed:

```typescript
import type { SheetRange, Color } from "@rowsncolumns/spreadsheet";

const navigateToSheetRange = useNavigateToSheetRange();
// Type: (range: SheetRange, flash?: boolean, color?: Color, duration?: number) => void

const [showLoader, hideLoader] = useLoadingIndicator();
// Type: [() => void, () => void]

const api = useSpreadsheetApi();
// Type: SpreadsheetAPI | null
```

## Troubleshooting

### useNavigateToSheetRange not working

Ensure you're inside `SpreadsheetProvider`:

```tsx
<SpreadsheetProvider>
  <YourComponent />  {/* Hook works here */}
</SpreadsheetProvider>
```

### LoadingIndicator not showing

Verify the component is rendered:

```tsx
<LoadingIndicator />  {/* Must be present */}
```

### useSpreadsheetApi returns null

The API is only available after the spreadsheet is mounted:

```tsx
useEffect(() => {
  if (api) {
    // API is ready
  }
}, [api]);
```
