Examples
Case 9: Security & Data Protection

Case 9: Security & Data Protection

This example demonstrates advanced security features in GridSheet, including data masking, clipboard protection, and custom security functions for password management.

Implementation Guide

📄 View Source Code

Masking Display Values with renderString

To show a partially masked value in the grid while keeping the raw value intact in the data model, override renderString in a PolicyMixinType.

const securityPolicy = new Policy({
  mixins: [
    {
      renderString({ value }: RenderProps<string>) {
        const str = String(value);
        if (str.length <= 2) return str;
        // Show only first 2 characters; asterisks for the rest
        return `${str.substring(0, 2)}${'*'.repeat(str.length - 2)}`;
      },
    },
  ],
});

The actual cell value remains unchanged — only the visual output is masked. This means formulas that reference the cell still receive the true value.

Clipboard Protection with serializeForClipboard

serializeForClipboard is called when a cell is copied to the clipboard. Returning a replacement string here prevents the raw value from leaking via Ctrl+C.

serializeForClipboard({ point, sheet }) {
  const cellValue = sheet.getSerializedValue({ point }) ?? '';
  // Replace every character with an asterisk
  return '*'.repeat(cellValue.length);
},

Combine this with renderString in the same mixin object to get both display masking and clipboard protection in a single policy.

Hiding the Formula Bar with showFormulaBar: false

Even with display masking in place, the formula bar would expose the raw cell value when a masked cell is selected. Disable it entirely with the showFormulaBar option.

<GridSheet
  book={book}
  options={{ showFormulaBar: false }}
  initialCells={...}
/>

Custom Functions via BaseFunction

Extend BaseFunction to add spreadsheet functions that operate on cell values. The main method receives the resolved argument values and returns the result.

import { BaseFunction } from '@gridsheet/react-core';
 
const SecureHashFunction = class extends BaseFunction {
  example = 'SECURE_HASH("password123")';
  helpText = ['Creates a hash of the input text'];
  defs = [{ name: 'text', description: 'Text to hash', acceptedTypes: ['string'] }];
 
  protected main(text: string) {
    let hash = 0;
    for (let i = 0; i < text.length; i++) {
      const char = text.charCodeAt(i);
      hash = (hash << 5) - hash + char;
      hash = hash & hash; // 32-bit integer
    }
    return Math.abs(hash).toString(16);
  }
};

Register it under a lowercase key in additionalFunctions. The formula name in the grid is that key uppercased: =SECURE_HASH(C1).

const book = useSpellbook({
  additionalFunctions: {
    secure_hash:    SecureHashFunction,
    validate_email: ValidateEmailFunction,
    encrypt_level:  EncryptLevelFunction,
  },
  policies: { security: securityPolicy },
});

Preventing Numeric Auto-coercion with a Dedicated Policy

Cell values that look like integers (e.g., "001") can be silently coerced to numbers. To keep them as strings, apply a minimal policy whose renderString forces the value through String().

const idPolicy = new Policy({
  mixins: [{
    renderString({ value }: any) {
      return String(value ?? '');
    },
  }],
});

Assign it to the ID column: A: { policy: 'id' }.

Selective Policy Application

Sensitive policies only need to be assigned to the columns that hold sensitive data. All other columns continue to use the default behavior.

cells: {
  C: { policy: 'security' },  // Password column — masked + clipboard protected
  A: { policy: 'id' },        // ID column — string-forced only
  // B and D use default policy
}