---
id: "packages/active-helpers"
title: "active-helpers"
description: "Small, dependency-free helpers several Active packages must agree on exactly - CSV and TSV serialization, PDF font rules and the menu pipeline."
url: "/packages/active-helpers"
locale: "en"
revision: "0494e9a80584bd6e"
---

# active-helpers

`@workspace/active-helpers` holds the helpers that [active-grid](/packages/active-grid),
[active-charts](/packages/active-charts) and [active-geo](/packages/active-geo) share: one owner,
one folder, one version, instead of a copy in each. Every module is plain TypeScript without a
single import, so it runs in a browser, in Node.js and in a worker alike. An application may use
the helpers too.

**Example: A row for a file and for the clipboard**

Client: Runs entirely in your browser. Source: `examples/helpers/delimited-text.tsx`.

```tsx
// apps/docs/examples/helpers/delimited-text.tsx
'use client';

import {useState} from 'react';

import {
  csvRow,
  neutralizeFormula,
  tsvRow,
} from '@workspace/active-helpers/serialization';
import {Input} from '@workspace/active-ui/components/primitives/input';
import {Label} from '@workspace/active-ui/components/primitives/label';

/** One row for a file and for the clipboard, safe to open in a spreadsheet. */
export default function DelimitedText() {
  const [cell, setCell] = useState('=HYPERLINK("http://example.com")');
  const row = ['ORD-00042', cell, 'line one\nline two', 12.5];
  return (
    <div className="flex w-full max-w-xl flex-col gap-4">
      <div className="flex flex-col gap-1.5">
        <Label htmlFor="helpers-cell">A cell value someone typed</Label>
        <Input
          id="helpers-cell"
          value={cell}
          onChange={(event) => setCell(event.target.value)}
        />
      </div>
      <dl className="grid grid-cols-[auto_1fr] gap-x-4 gap-y-2 text-sm">
        <dt className="text-muted-foreground">neutralizeFormula</dt>
        <dd className="font-mono break-all" data-helpers="neutralized">
          {neutralizeFormula(cell)}
        </dd>
        <dt className="text-muted-foreground">csvRow (;)</dt>
        <dd
          className="font-mono break-all whitespace-pre-wrap"
          data-helpers="csv"
        >
          {csvRow(row, ';')}
        </dd>
        <dt className="text-muted-foreground">tsvRow</dt>
        <dd
          className="font-mono break-all whitespace-pre-wrap"
          data-helpers="tsv"
        >
          {tsvRow(row).replaceAll('\t', '→')}
        </dd>
      </dl>
    </div>
  );
}
```

## Entry points

| Import | Contents |
| --- | --- |
| `@workspace/active-helpers/serialization` | `csvField`, `csvRow`, `tsvField`, `tsvRow`, `neutralizeFormula`, `DEFAULT_CSV_DELIMITER`, `serializeDecimals` |
| `@workspace/active-helpers/export-fonts` | which text a jsPDF-class backend can draw, font byte classification, the four PDF font styles, covering-family choice |
| `@workspace/active-helpers/menu-items` | the menu item contract and `resolveMenuItems`, the one pipeline every Active menu runs through |

There is no root entry. Every export and its contract are in the [API reference](/packages/active-helpers/api).

## What it guarantees

- **Formula safety.** A value that a spreadsheet would execute (`=`, `@`, or a sign followed by an
  expression) gets a leading apostrophe in every CSV and TSV field.
- **Any delimiter is safe.** CSV fields are always quoted; TSV fields are quoted only where a tab,
  newline or quote would break the row, and never stripped.
- **One menu rule.** Filtering, separators and the destructive tail are resolved the same way in
  every product's menu.

## Receiving it

You rarely request it yourself: it comes along with a product that needs it. On its own, request
it as an owner (`--owners active-helpers`) and declare
`"@workspace/active-helpers": "workspace:*"`; then follow [Receiving packages](/receiving-packages).

## Origin

The five helper modules were the `portable-helpers` selection of `@workspace/active-utils` 2.0.0 in
the repository the packages came from. Foundation formed this package from that selection on
2026-10-21, so the helpers have one owner and travel as one canonical folder. The behaviour is
unchanged; only the package name in the import differs.
