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 CodeMasking 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
}