{
  "id": "componentId",
  "title": "Component Name",
  "caption": ["Item", "Items"],

  "target": "content", //(default) For editing items in the content area (will be added to the Component Toolbar)
  "target": "page",    //For rendering page-level components such as menus and breadcrumbs
  "target": "site",    //For generating site-level pages like redirects

  // Icons can be specified using Google Material icon font name, as SVG, or as HTML
  //  1. For Material Icon:"'material:<Google Material Icon Font Name>". Example: "material:photo_library"
  //  2. For SVG: "svg:<SVG Code>". Example: "svg:<svg xmlns='http://www.w3.org/2000/svg' height='24' viewBox='0 0 24 24' width='24'><path d='M0 0h24v24H0z' fill='none'/><path d='M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z'/></svg>"
  //  3. For HTML: "html:<HTML Code>". Example: "html:<i class="iconClass">iconName</i>"
  "icon": "material:photo_library",

  // There are two hooks that can be used in the render process
  // 1. onBeforeRender(renderConfig): this hook is called before rendering the component. The renderConfig contains
  //    an object that can be manipulated before being used to render the component.
  // 2. onRender(element, data, properties, cms, component): this hook is called when the component is rendered.
  "js": "...Content...", // Prepended by <templateBaseFileName>.js

  //Local templates can be used to load templates from the CMS
  "templates": {
    "editor": "...Content...",  // Prepended by <templateBaseFileName>.templates.editor.ejs
    "publish": "...Content...", // Prepended by <templateBaseFileName>.templates.publish.ejs
  },

  //Remote templates can be used to load templates from a remote site on edit or publish
  "remote_templates": {
    "editor": "https://server/templates/components/content_element_name.html?source=1&_=%%%timestamp%%%",
    "publish": "https://server/templates/components/content_element_name.html?source=1&_=%%%timestamp%%%",
  },

  "optimization": {
    "bare_ejs_templates": false,  // "true" disables server-side editor template parsing (and downloads remote templates client-side)
                                  //  May be slightly faster, but will disallow using tags like "jsh-foreach-item" in component template
  },

  "editor_placeholder": {
    "items_empty": true,    //Display a placeholder if no items are entered, when component.multiple_items
    "invalid_fields": true, //Display a placeholder for an item when field validation fails
                            //  (on single item, or on component.multiple_items when the jsh-foreach-items tag is used)
  },

  "options": {
    //Editor Options
    "component_preview_size": "expand", //Defines how the component preview will be rendered when editing Component Data in the Grid and Form
                                        //  "expand" (default) expands preview to width of container.  "collapse" shrinks container to fit preview
    "editor_container": "block",        //Defines how content components will be displayed in the editor preview (*on publish, content components do not have a container)
                                        //  "block" (default) displays the component in a separate block.  "inline" enables components that flow with existing text
    "menu_parents": ["Parent 1","Parent 2"], //(Array <string>) Parent menu hierarchy, so that the content component will be grouped under a flyout menu
    "menu_visibility": "return cms.controller.page.page_template_id=='two-column';" //JS Function that returns a boolean of whether or not to show the content component in the menu
                                                                                    //  Parameters: jsh, cms, component, window (DOM)
  },
  
  //The following property is a shortcut for "properties.fields".  Values are appended to the properties.fields array
  "component_properties": [ ... field array ... ],
  // or, if defined as an object, component_properties is a shortcut for "properties"
  "component_properties": { ... },

  //The following property is a shortcut for "data.fields".  Values are appended to the data.fields array
  "item_properties": [ ... field array ... ],
  // or, if defined as an object, item_properties is a shortcut for "data"
  "item_properties": { ... },

  "multiple_items": false, //(default) For Content Components - enable only one data item (ex. Banner). Sets data.layout = "form"
  "multiple_items": true,  //For Content Components - enable multiple data items (ex. Listing). Sets data.layout = "grid_preview"

  "properties": {
    "ejs": "...Content...", // Prepended by <templateBaseFileName>.properties.ejs
    "css": "...Content...", // Prepended by <templateBaseFileName>.properties.css
    "js": "...Content...", // Prepended by <templateBaseFileName>.properties.js
    "fields": [
      { "name": "cssStyle", "caption": "CSS Style", "type": "varchar", "length": 1024,
        "control": "textbox", "controlstyle": "width:260px", "validate": ["MaxLength:1024"]},

      { "name": "cssClass", "caption": "CSS Class", "type": "varchar", "length": 1024,
        "control": "textbox", "controlstyle": "width:260px", "validate": ["MaxLength:1024"]}
    ]
  },

  "data": {
    "layout": "grid_preview", // Can also be "form", "grid"
    "ejs": "...Content...", // Prepended by <templateBaseFileName>.data.ejs
    "css": "...Content...", // Prepended by <templateBaseFileName>.data.css
    "js": "...Content...", // Prepended by <templateBaseFileName>.data.js
    "templates": {
      "gridRowPreview": ".rowPreview", // CSS selector for element defined in "ejs" used to render a grid_preview row component preview
      "itemPreview": ".itemPreview" // CSS selector for element defined in "ejs" used to render a form component preview
    },
    "popup": [1000, 200], // Width and height of grid popup window
    "fields": [
      // To use a link browser, set control to "link_browser":
      { "name": "link", "control": "link_browser", "caption": "Link", "length": 1024, "validate": ["MaxLength:1024"], "controlstyle": "width:320px"},
      // To use a media browser, set control to "media_browser":
      { "name": "image", "control": "media_browser", "caption": "Image", "length": 1024, "validate": ["MaxLength:1024"], "controlstyle": "width:320px"},
      // To use a WYSIWYG HTML editor:
      //  1. Add the appropriate attribute to the element in the
      //     EJS template that you wish to make editable
      //    a. To use a full featured editor use the attribute: data-component-full-editor="<fieldName>"
      //    b. To use a title only editor use the attribute: data-component-title-editor="<fieldName>"
      // 2. Add the following field where the "name" property matches the attribute value from above.
      { "name": "body", "type": "varchar", "control": "hidden", "caption": "" },

      { "name": "content_layout", "type": "varchar", "control": "dropdown", "caption": "Content", "default": "all",
        "lov": { "values": { "all": "Title + Body", "title": "Title Only", "body": "Body Only", "none": "None" } }}
    ],

    // "oninit" hook for the form/item preview. Other standard jsHarmony hooks as available as well.
    "oninit": "_this.oninit_form()",

    // Additional hooks are available for the component editor dialogs, and defined in the data.js file
    // To use a component editor dialog hook, in the data.js file, write: this.[hook name] = function
    //    ex.   this.onBeforeRenderGridRow = function(renderConfig){ ... }
    // 1. onBeforeRenderGridRow(renderConfig): this hook is called before rendering a grid row. The renderConfig contains
    //    an object that can be manipulated before being used to render the grid row.
    // 2. onRenderGridRow(element, data, properties, cms, component): this hook is called when the grid row is rendered.
    // 3. onBeforeRenderDataItemPreview(renderConfig): this hook is called before rendering the item preview. The renderConfig contains
    //    an object that can be manipulated before being used to render the item.
    // 4. onRenderDataItemPreview(element, data, properties, cms, component): this hook is called when the item preview is rendered.
    //    If onRenderDataItemPreview returns a promise, then that will be executed before further events are attached
  },

  "export": [
    //Multiple exports are supported - add an entry for each file that will be generated
    {
      "export_path": "path/to/file.php",

      "template": "EJS that will be used in the export, ex <%=sitemap.root.text%>",
      "remote_template": "https://server/templates/components/content_element_name.export.routes.html?source=1&_=%%%timestamp%%%",
      //If both "template" and "remote_template" are defined, "template" value will be prepended to "remote_template" content
      //If no "template" or "remote_template" are defined, the current file will be used as the template

      "menu_tag": "main", //(Optional) Menu to be loaded into the "menu" variable for rendering
      "data": [{"itemField1":"value","itemField2":"value"},{"itemField1":"value1","itemField2":"value"}], //(Optional) Data that will be passed to the component for rendering
      "properties": {"propertyName":"propertyValue"}, //(Optional) Properties that will be passed to the component for rendering
    },
    //Multiple files can be generated from one template using the "addFile" function
    //If no path is specified, the template itself will need to call the "addFile" function to produce output files
    {
      "template": "<% addFile('config/file1.php', 'File content 1'); addFile('config/file2.php', 'File content 2'); %>",
    }
  ]
}