Component Scripts

Overview

Every block and component in the Cynosure Design System can have a script.js file alongside its template.hbs, style.scss, and {name}.js configuration. This file is compiled by Handoff and displayed in the component preview, giving downstream developers a clear picture of what JavaScript a block requires.

Code
blocks/accordion-simple/ ├── accordion-simple.js — Handoff config, properties schema, previews ├── template.hbs — Handlebars template ├── style.scss — Component-scoped SCSS └── script.js — JavaScript (imports shared utilities and/or custom logic)

The @shared annotation

Most blocks delegate to a shared utility in js/components/. Rather than leaving a bare import, add a JSDoc file header that documents what the utility does in the context of this block. Handoff surfaces this comment in the preview UI.

JavaScript
1/** 2 * Accordion Simple Block 3 * 4 * Expandable content panels using jQuery slide animations. 5 * Only one panel is open at a time within a given .c-accordion element. 6 * 7 * @shared accordion 8 * Trigger: .c-accordion__toggle 9 * Behavior: Expands the clicked panel; collapses all siblings 10 * Library: jQuery (slideUp / slideToggle) 11 * 12 * @see /guidelines/javascript/shared-utilities 13 */ 14import '../../js/components/accordion.js';

What each section means:

  • Block title and description — one sentence stating what the block does and what the JavaScript handles
  • @shared <utility-name> — names the shared utility being imported; describes the DOM selector it attaches to and the visible behavior
  • @see — links to the relevant documentation page for the utility or convention

Multiple shared utilities

When a block imports more than one utility, add a @shared entry for each:

JavaScript
1/** 2 * Download Block 3 * 4 * Filterable download library with lightbox popups for brochure downloads. 5 * 6 * @shared popup 7 * Trigger: .js-open-content-popup-brochure, .js-open-content-popup-asset 8 * Behavior: Opens Magnific Popup inline modal; injects Pardot iframe src on open 9 * 10 * @shared selects 11 * Trigger: .c-select select 12 * Behavior: Initialises Select2 on filter dropdowns; hides native select 13 * 14 * @see /guidelines/javascript/popup 15 * @see /guidelines/javascript/selects 16 */ 17import '../../js/components/popup.js'; 18import '../../js/components/selects.js';

Adding custom logic

When a block needs logic beyond what a shared utility provides, write it after the imports. Always scope all DOM queries to the block element and support multiple instances on a single page.

JavaScript
1/** 2 * Product Showcase Block 3 * 4 * Filterable product grid with animated card transitions. 5 * 6 * @shared selects 7 * Trigger: .c-select select 8 * Behavior: Select2 on the category filter dropdown 9 * 10 * @see /guidelines/javascript/selects 11 * @see /guidelines/javascript/component-scripts 12 */ 13import '../../js/components/selects.js'; 14 15document.addEventListener('DOMContentLoaded', () => { 16 document.querySelectorAll('[data-component="product-showcase"]').forEach(block => { 17 const filterSelect = block.querySelector('.js-filter-select'); 18 const cards = block.querySelectorAll('.js-product-card'); 19 20 if (!filterSelect) return; 21 22 filterSelect.addEventListener('change', () => { 23 const selected = filterSelect.value; 24 25 cards.forEach(card => { 26 const match = selected === 'all' || card.dataset.category === selected; 27 card.classList.toggle('is-hidden', !match); 28 }); 29 }); 30 }); 31});

Rules for custom logic:

  • Use const and let — never var
  • Use document.querySelectorAll('[data-component="..."]').forEach(block => {...}) — never target a single global element
  • Scope all DOM queries to block — never use document.getElementById
  • Use class="js-*" selectors as JavaScript hooks — not id="*" attributes
  • Remove all console.log before committing

Blocks without a script.js

Blocks that require no JavaScript do not need a script.js. Handoff will display a "no script required" note in the preview. Do not create an empty file.

JSDoc header fields

TagRequired?Purpose
Block title + description (first paragraph)YesHuman-readable summary shown in the Handoff UI
@shared <utility>If delegating to a shared moduleDocuments the shared utility, its DOM trigger, and its behavior
@requires <library>For custom logic that needs a libDeclares the external library dependency
@see <url>Yes (at least one)Links to the relevant guideline page