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:
<template> <div class="sample-tutorial"> <div class="sample-container"> <gc-spread-sheets :hostStyle="hostStyle" @workbookInitialized="initSpread"> <gc-worksheet></gc-worksheet> <gc-worksheet></gc-worksheet> <gc-worksheet></gc-worksheet> <gc-worksheet></gc-worksheet> <gc-worksheet></gc-worksheet> </gc-spread-sheets> </div> <div class="options-container"> <div class="info-tip">The left side displays preset named templates. Switch to the Playground sheet to apply templates.</div> <div class="section-title">Apply Template</div> <div class="option-row"> <label for="templateSelect">Template:</label> <select id="templateSelect" v-model="selectedTemplate"> <option v-for="name in templateNames" :key="name" :value="name">{{ name }}</option> </select> </div> <div class="option-row"> <label for="targetRange">Target Range:</label> <input id="targetRange" v-model="targetRange" type="text" placeholder="e.g. A1:A10" /> </div> <div class="option-row"> <input id="applyBtn" type="button" value="Apply Template" @click="applyTemplate" /> </div> <div class="section-title">Create From Cell</div> <div class="option-row"> <label for="newTemplateName">Template Name:</label> <input id="newTemplateName" v-model="newTemplateName" type="text" placeholder="Enter template name" /> </div> <div class="option-row"> <label>Options:</label> <div class="checkbox-row"> <input id="optStyle" v-model="createOptions.style" type="checkbox" /> <label for="optStyle">Style</label> </div> <div class="checkbox-row"> <input id="optConditionalFormat" v-model="createOptions.conditionalFormat" type="checkbox" /> <label for="optConditionalFormat">Conditional Format</label> </div> <div class="checkbox-row"> <input id="optDataValidation" v-model="createOptions.dataValidation" type="checkbox" /> <label for="optDataValidation">Data Validation</label> </div> <div class="checkbox-row"> <input id="optCellState" v-model="createOptions.cellState" type="checkbox" /> <label for="optCellState">Cell State</label> </div> </div> <div class="option-row"> <input id="createFromCellBtn" type="button" value="Create From Cell" @click="createTemplate" /> </div> <div class="section-title">Template Management</div> <div class="option-row"> <label for="templateList">Registered Templates:</label> <select id="templateList" v-model="selectedListTemplate" size="12"> <option v-for="name in templateNames" :key="name" :value="name">{{ name }}</option> </select> </div> <div class="option-row"> <input id="removeBtn" type="button" value="Remove Selected" @click="removeTemplate" /> <input id="clearBtn" type="button" value="Clear All" @click="clearTemplates" /> </div> </div> </div> </template> <script setup> import { onBeforeUnmount, reactive, ref } from 'vue'; import { DEFAULT_CREATE_OPTIONS, DEFAULT_TARGET_RANGE, applyTemplateToRange, clearNamedTemplates, createTemplateFromSelection, getOrderedRegisteredTemplateNames, initializeNamedCellTemplateDemo, removeNamedTemplate, syncSelectionTargetRange } from './demo-logic.js'; const hostStyle = { width: '100%', height: '100%' }; const spread = ref(null); const selectionCleanup = ref(null); const templateNames = ref([]); const selectedTemplate = ref(''); const selectedListTemplate = ref(''); const targetRange = ref(DEFAULT_TARGET_RANGE); const newTemplateName = ref(''); const createOptions = reactive({ ...DEFAULT_CREATE_OPTIONS }); function syncTemplateState(names) { templateNames.value = names; selectedTemplate.value = names.indexOf(selectedTemplate.value) !== -1 ? selectedTemplate.value : (names[0] || ''); selectedListTemplate.value = names.indexOf(selectedListTemplate.value) !== -1 ? selectedListTemplate.value : (names[0] || ''); } function initSpread(workbook) { spread.value = workbook; initializeNamedCellTemplateDemo(workbook); syncTemplateState(getOrderedRegisteredTemplateNames(workbook)); if (selectionCleanup.value) { selectionCleanup.value(); } selectionCleanup.value = syncSelectionTargetRange(workbook, function (value) { targetRange.value = value; }); } function withSpread(action) { if (!spread.value) { return; } try { action(spread.value); } catch (error) { window.alert(error.message); } } function applyTemplate() { withSpread(function (workbook) { applyTemplateToRange(workbook, selectedTemplate.value, targetRange.value); }); } function createTemplate() { withSpread(function (workbook) { syncTemplateState(createTemplateFromSelection(workbook, newTemplateName.value, createOptions)); newTemplateName.value = ''; }); } function removeTemplate() { withSpread(function (workbook) { syncTemplateState(removeNamedTemplate(workbook, selectedListTemplate.value)); }); } function clearTemplates() { withSpread(function (workbook) { syncTemplateState(clearNamedTemplates(workbook)); }); } onBeforeUnmount(function () { if (selectionCleanup.value) { selectionCleanup.value(); } }); </script> <style> 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; } </style>
<!DOCTYPE html> <html style="height:100%;font-size:14px;"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <title>SpreadJS VUE</title> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/vue3/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <script src="$DEMOROOT$/en/vue3/node_modules/systemjs/dist/system.src.js"></script> <script src="./systemjs.config.js"></script> <script src="./compiler.js" type="module"></script> <script> var System = SystemJS; System.import("./src/app.js"); System.import('$DEMOROOT$/en/lib/vue3/license.js'); </script> </head> <body> <div id="app"></div> </body> </html>
(function (global) { SystemJS.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true }, paths: { // paths serve as alias 'npm:': 'node_modules/', 'cdn:': 'https://cdn.mescius.io/demoapps/packages/spreadjs/19.1.2-master-2026-06-10-2131/' }, packageConfigPaths: [ './node_modules/*/package.json', "./node_modules/@mescius/*/package.json", "./node_modules/@babel/*/package.json", "./node_modules/@vue/*/package.json" ], map: { 'vue': "npm:vue/dist/vue.esm-browser.js", 'tiny-emitter': 'npm:tiny-emitter/index.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', "systemjs-babel-build": "npm:systemjs-plugin-babel/systemjs-babel-browser.js", '@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-vue': 'cdn:@mescius/spread-sheets-vue/index.js', }, meta: { '*.css': { loader: 'systemjs-plugin-css' }, '*.vue': { loader: "../plugin-vue/index.js" } } }); })(this);