# Custom formula evaluation

Spreadsheet is completely headless, you can use your own formula parser and evaluator. You can choose to use client-side or server side evaluation.

## Formula parser

The default formula parser is based on open source `fast-formula-parser` . All formula calculations are done on the client-side.

## Custom functions

If you are using `useSpreadsheetState` hook to render the data of the Spreadsheet, its easy to add custom functions.

### 1. Create your named function

```typescript
import type FormulaParser from "@rowsncolumns/fast-formula-parser";
import type { FunctionArgument } from "@rowsncolumns/calculator";

const SAY_WORLD = (parser: FormulaParser, arg: FunctionArgument) => {
  if (arg.value === 'hello') {
    return 'world'
  }
}
```

### 2. Create a function description

Function description appears in the dropdown when users enters the formula

```json
const functionDescriptions = [{
  datatype: "Text",
  title: "SAY_WORLD",
  syntax: "SAY_WORLD(value)",
  description: "Returns world if user says hello.",
  example: "SAY_WORLD('hello')",
  usage: ["SAY_WORLD('oops')"],
  parameters: [
    {
      title: "value",
      description: "The text that user enters.",
    },
  ],
}]
```

### 3. Pass the function and description to `useSpreadsheetState`

```tsx
const MySpreadsheet = () => {
  const {} = useSpreadsheetState({
    functions: {
      SAY_WORLD
    }
  })
  
  return (
    <CanvasGrid
      functionDescriptions={functionDescriptions}
    />
  )
}
```

Your new custom formula should be ready to use

## Using your own formula evaluation

There are 2 ways to use a custom formula evaluation engine.

### 1. enqueueCalculation in useSpreadsheetState

```tsx
import type { CellCoordinate } from "@rowsncolumns/dag";
const MySpreadsheet = () => {
  const {} = useSpreadsheetState({
    enqueueCalculation: (type: 'add' | 'remove' | 'dirty', position: CellCoordinate) => {
      // Process calculations and update sheet
      const value = getCellValue (position)
      if (value.str(0) === '=') {
        const result = myCustomEvaluationQueue(value)
        // Call setState to update result
        onChangeSheetData()
      }  
    }
  })
  
  return (
    <CanvasGrid
    />
  )
}
```

If you are using a custom calculator, assuming that you are maintaining the cell dependency graph, you will also have to provide `getDependents` and `getPrecendents` API to `useSpreadsheetState`

### 2. Sending results to back-end

You can either use above method to send the calculation to the back-end to evaluate formulas or you can use the headless-ui, without `useSpreadsheetState` hook

```typescript
import type { CellCoordinate } from "@rowsncolumns/dag";
const MySpreadsheet = () => {
  
  return (
    <CanvasGrid
      onChange={(sheetId, rowIndex, columnIndex, value: string) => {
        if (value.str(0) === '=') {
          const result = await fetch("post", { value })
          onChangeSheetData({ result })
        }
      })
    />
  )
}
```

## Web Worker support

`@rowsncolumns/calculation-worker` package supports calculation via a web worker. The cell dependency graphs is still on the main UI thread, but formula parsing and calculation happens on a web worker


---

# 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/custom-formula-evaluation.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.
