Named Cell Template

SpreadJS supports named cell templates, which allow you to create reusable cell configuration templates that combine style, conditional formatting, cell states, and data validation. You can register a template in a workbook, create one from an existing cell, and apply it to ranges across worksheets.

Introduction The Named Cell Templates feature allows you to define reusable cell configuration templates that can be applied to cells or ranges. Each template can contain style, conditional formats, data validations, and cell states. You can access the named cell templates manager through the workbook instance: Add a Template Use add(name, template) to register a new template: Create Template from Cell Use createFromCell(name, sheet, row, col, options) to create a template from an existing cell's configuration: Apply Template Use sheet.applyNamedCellTemplate(name, address) to apply a template to a range: Or use cellRange.applyNamedCellTemplate(name): Manage Templates Template Structure The template object follows the INamedCellTemplate interface:
import * as React from 'react'; import { createRoot } from 'react-dom/client'; import './styles.css'; import { App } from './app-func'; createRoot(document.getElementById('app')).render(<App />);
import * as React from 'react'; import { SpreadSheets, Worksheet } from '@mescius/spread-sheets-react'; import { DEFAULT_CREATE_OPTIONS, DEFAULT_TARGET_RANGE, applyTemplateToRange, clearNamedTemplates, createTemplateFromSelection, getOrderedRegisteredTemplateNames, initializeNamedCellTemplateDemo, removeNamedTemplate, syncSelectionTargetRange } from './demo-logic'; export function App() { var spreadRef = React.useRef(null); var cleanupRef = React.useRef(null); var templateState = React.useState([]); var templateNames = templateState[0]; var setTemplateNames = templateState[1]; var selectedTemplateState = React.useState(''); var selectedTemplate = selectedTemplateState[0]; var setSelectedTemplate = selectedTemplateState[1]; var selectedListState = React.useState(''); var selectedListTemplate = selectedListState[0]; var setSelectedListTemplate = selectedListState[1]; var targetRangeState = React.useState(DEFAULT_TARGET_RANGE); var targetRange = targetRangeState[0]; var setTargetRange = targetRangeState[1]; var newTemplateNameState = React.useState(''); var newTemplateName = newTemplateNameState[0]; var setNewTemplateName = newTemplateNameState[1]; var createOptionsState = React.useState(DEFAULT_CREATE_OPTIONS); var createOptions = createOptionsState[0]; var setCreateOptions = createOptionsState[1]; function syncTemplateState(names) { setTemplateNames(names); setSelectedTemplate(function (previous) { if (previous && names.indexOf(previous) !== -1) { return previous; } return names[0] || ''; }); setSelectedListTemplate(function (previous) { if (previous && names.indexOf(previous) !== -1) { return previous; } return names[0] || ''; }); } function initSpread(spread) { spreadRef.current = spread; initializeNamedCellTemplateDemo(spread); syncTemplateState(getOrderedRegisteredTemplateNames(spread)); if (cleanupRef.current) { cleanupRef.current(); } cleanupRef.current = syncSelectionTargetRange(spread, setTargetRange); } function withSpread(action) { if (!spreadRef.current) { return; } try { action(spreadRef.current); } catch (error) { window.alert(error.message); } } function handleApplyTemplate() { withSpread(function (spread) { applyTemplateToRange(spread, selectedTemplate, targetRange); }); } function handleCreateTemplate() { withSpread(function (spread) { syncTemplateState(createTemplateFromSelection(spread, newTemplateName, createOptions)); setNewTemplateName(''); }); } function handleRemoveTemplate() { withSpread(function (spread) { syncTemplateState(removeNamedTemplate(spread, selectedListTemplate)); }); } function handleClearTemplates() { withSpread(function (spread) { syncTemplateState(clearNamedTemplates(spread)); }); } function updateCreateOption(name, checked) { setCreateOptions(function (previous) { return Object.assign({}, previous, { [name]: checked }); }); } return ( <div className="sample-tutorial"> <div className="sample-container"> <SpreadSheets hostStyle={{ width: '100%', height: '100%' }} workbookInitialized={initSpread}> <Worksheet /> <Worksheet /> <Worksheet /> <Worksheet /> <Worksheet /> </SpreadSheets> </div> <div className="options-container"> <div className="info-tip">The left side displays preset named templates. Switch to the Playground sheet to apply templates.</div> <div className="section-title">Apply Template</div> <div className="option-row"> <label htmlFor="templateSelect">Template:</label> <select id="templateSelect" value={selectedTemplate} onChange={function (event) { setSelectedTemplate(event.target.value); }}> {templateNames.map(function (name) { return <option key={name} value={name}>{name}</option>; })} </select> </div> <div className="option-row"> <label htmlFor="targetRange">Target Range:</label> <input id="targetRange" type="text" value={targetRange} placeholder="e.g. A1:A10" onChange={function (event) { setTargetRange(event.target.value); }} /> </div> <div className="option-row"> <input type="button" id="applyBtn" value="Apply Template" onClick={handleApplyTemplate} /> </div> <div className="section-title">Create From Cell</div> <div className="option-row"> <label htmlFor="newTemplateName">Template Name:</label> <input id="newTemplateName" type="text" value={newTemplateName} placeholder="Enter template name" onChange={function (event) { setNewTemplateName(event.target.value); }} /> </div> <div className="option-row"> <label>Options:</label> <div className="checkbox-row"> <input id="optStyle" type="checkbox" checked={createOptions.style} onChange={function (event) { updateCreateOption('style', event.target.checked); }} /> <label htmlFor="optStyle">Style</label> </div> <div className="checkbox-row"> <input id="optConditionalFormat" type="checkbox" checked={createOptions.conditionalFormat} onChange={function (event) { updateCreateOption('conditionalFormat', event.target.checked); }} /> <label htmlFor="optConditionalFormat">Conditional Format</label> </div> <div className="checkbox-row"> <input id="optDataValidation" type="checkbox" checked={createOptions.dataValidation} onChange={function (event) { updateCreateOption('dataValidation', event.target.checked); }} /> <label htmlFor="optDataValidation">Data Validation</label> </div> <div className="checkbox-row"> <input id="optCellState" type="checkbox" checked={createOptions.cellState} onChange={function (event) { updateCreateOption('cellState', event.target.checked); }} /> <label htmlFor="optCellState">Cell State</label> </div> </div> <div className="option-row"> <input type="button" id="createFromCellBtn" value="Create From Cell" onClick={handleCreateTemplate} /> </div> <div className="section-title">Template Management</div> <div className="option-row"> <label htmlFor="templateList">Registered Templates:</label> <select id="templateList" size="12" value={selectedListTemplate} onChange={function (event) { setSelectedListTemplate(event.target.value); }}> {templateNames.map(function (name) { return <option key={name} value={name}>{name}</option>; })} </select> </div> <div className="option-row"> <input type="button" id="removeBtn" value="Remove Selected" onClick={handleRemoveTemplate} /> <input type="button" id="clearBtn" value="Clear All" onClick={handleClearTemplates} /> </div> </div> </div> ); }
<!doctype html> <html style="height:100%;font-size:14px;"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/react/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <!-- SystemJS --> <script src="$DEMOROOT$/en/react/node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('$DEMOROOT$/en/lib/react/license.js').then(function () { System.import('./src/app'); }); </script> </head> <body> <div id="app"></div> </body> </html>
html, body, #app { height: 100%; margin: 0; } body { position: absolute; top: 0; right: 0; bottom: 0; left: 0; } .sample-tutorial { position: relative; display: flex; height: 100%; overflow: hidden; } .sample-container { width: calc(100% - 320px); height: 100%; overflow: hidden; } .options-container { width: 320px; padding: 12px; height: 100%; box-sizing: border-box; background: #fbfbfb; overflow: auto; border-left: 1px solid #e5e5e5; } .info-tip { background: #e7f3ff; border-left: 3px solid #2196f3; border-radius: 4px; padding: 8px 10px; font-size: 13px; color: #333; line-height: 1.4; margin-bottom: 8px; } .section-title { font-weight: bold; font-size: 13px; border-bottom: 1px solid #ddd; padding-bottom: 4px; margin-top: 16px; margin-bottom: 8px; } .section-title:first-child { margin-top: 0; } .option-row { font-size: 14px; padding: 2px 0; margin-top: 6px; } .option-row label { display: block; margin-bottom: 4px; } .checkbox-row { margin: 4px 0; } .checkbox-row label { display: inline; margin-left: 4px; } input[type=text] { width: 100%; box-sizing: border-box; padding: 4px 6px; } select { width: 100%; padding: 4px; } input[type=button] { margin-top: 6px; display: block; width: 100%; padding: 6px 8px; cursor: pointer; }
(function (global) { System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true, react: true }, meta: { '*.css': { loader: 'css' } }, paths: { // paths serve as alias 'npm:': 'node_modules/', 'cdn:': 'https://cdn.mescius.io/demoapps/packages/spreadjs/19.1.1-master-2026-05-28-1420/' }, // map tells the System loader where to look for things map: { '@mescius/spread-sheets': 'cdn:@mescius/spread-sheets/index.js', '@mescius/spread-sheets-shapes': 'cdn:@mescius/spread-sheets-shapes/index.js', '@mescius/spread-sheets-slicers': 'cdn:@mescius/spread-sheets-slicers/index.js', '@mescius/spread-sheets-charts': 'cdn:@mescius/spread-sheets-charts/index.js', '@mescius/spread-sheets-react': 'cdn:@mescius/spread-sheets-react/index.js', '@grapecity/jsob-test-dependency-package/react-components': 'npm:@grapecity/jsob-test-dependency-package/react-components/index.js', 'react': 'npm:react/cjs/react.production.js', 'react-dom': 'npm:react-dom/cjs/react-dom.production.js', 'react-dom/client': 'npm:react-dom/cjs/react-dom-client.production.js', 'scheduler': 'npm:scheduler/cjs/scheduler.production.js', 'css': 'npm:systemjs-plugin-css/css.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', 'systemjs-babel-build':'npm:systemjs-plugin-babel/systemjs-babel-browser.js' }, // packages tells the System loader how to load when no filename and/or no extension packages: { src: { defaultExtension: 'jsx' }, "node_modules": { defaultExtension: 'js' }, } }); })(this);