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
Section titled “Implementation Guide”Masking Display Values with renderString
Section titled “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
Section titled “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
Section titled “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
Section titled “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
Section titled “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
Section titled “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}