{"_id":"59fb7735293c780010ce11bd","project":"55a6e72e8cc73e0d00096635","version":{"_id":"55a6e72f8cc73e0d00096638","project":"55a6e72e8cc73e0d00096635","hasReference":false,"__v":30,"hasDoc":true,"createdAt":"2015-07-15T23:05:19.125Z","releaseDate":"2015-07-15T23:05:19.125Z","categories":["55a6e7308cc73e0d00096639","55b7ed07aea7c8190058badb","5604567c0c78b00d0039b191","5605e6f23a93940d002b3e4a","5605f2bba4574a0d00811365","5605f309a4574a0d00811366","5608e3b98aedf50d0004cf8f","5608e4318aedf50d0004cf90","5608e6b5a7cc2f0d00d9754d","5608e6d331beb60d001b6560","5608f879a7cc2f0d00d97580","560b097887b71d0d000d3bd9","560b13cbafa0990d00979545","560b5cbec341310d00de2a01","560b5cd0c341310d00de2a02","566a35b81e08750d00a0c49b","566a3e8503b4b20d00d02a4a","567889d307bf6a0d0083edc8","569c8b7c15bb390d00db6f9d","56b254dc65ddf50d0076ba8f","57a8ebc4cdeea20e001d2a63","57e48a4000c8680e00fae6e7","5808216773557d0f00a1e428","58105ad54a8aa50f00aa4cba","58105bf298aea40f00afa3ba","58105f548a4aed0f00d67536","581061b898aea40f00afa3be","584b3de7e5f3a42300df6ef7","596839a75965d400155bb750","5b195f920059c20003083ad6"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.0.0","version":"1.0"},"category":{"_id":"581061b898aea40f00afa3be","__v":0,"project":"55a6e72e8cc73e0d00096635","version":"55a6e72f8cc73e0d00096638","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2016-10-26T07:56:40.278Z","from_sync":false,"order":12,"slug":"conditional-logic-examples","title":"Conditional-Logic Examples"},"user":"55a6caa022cfa321008e01d6","githubsync":"","__v":0,"parentDoc":null,"updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-11-02T19:51:17.890Z","link_external":false,"link_url":"","sync_unique":"","hidden":false,"api":{"settings":"","results":{"codes":[]},"auth":"required","params":[],"url":""},"isReference":false,"order":4,"body":"[block:html]\n{\n  \"html\": \"<!-- For screenshots: There's a row of Dynamic Tabs above a sizing-chart Snippet on this page: https://www.goruck.com/hoodie-eagle/ \\n...and a bottom Dropzone on this page: https://www.goruck.com/collections/shop-all/ -->\"\n}\n[/block]\nThis page outlines several techniques for enhancing Stencil themes with dynamic content injection. It covers:\n\n* [Why Dynamic Content?: Dropzones, Dynamic Tabs, and Snippets](#overview)\n* [Dropzones](#dropzones)\n* [Dynamic Tabs](#tabs)\n* [Snippets](#snippets)\n\nWe're gratefully sharing techniques devised by Ken Utting, Web Developer for BigCommerce client [goruck.com](https://www.goruck.com/):\n\n<a name=\"overview\"></a>\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Why Dynamic Content?: Dropzones, Dynamic Tabs, and Snippets\",\n  \"body\": \"At GORUCK, we've customized our Stencil theme ([Merchant](https://www.bigcommerce.com/theme/merchant-light/)) to provide several ways to update our site content without requiring changes to the theme itself. This allows our content folks to make changes to our theme without having to wait on our software developers.\\n\\nAlso, by pushing content out of the theme, these techniques reduce the differences between our customized theme and the out-of-the-box (base) theme – which makes it easier to [integrate ongoing updates](/docs/theme-updates-sync#isolate) into our theme. Finally, these techniques allow us share identical content across pages without copying and pasting.\\n\\nThree techniques in particular have proven useful to us. We call them [Dropzones](#dropzones), [Dynamic Tabs](#tabs), and [Snippets](#snippets). There is nothing particularly special to GORUCK about these techniques, so there is no reason you can't adopt them for your own store/theme.\\n\\n#### Building on the Control Panel\\n\\nThe BigCommerce control panel provides an HTML editor where you can enter custom content for Products, Categories, and custom static pages (`Storefront` > `Web Pages`). But we encountered these limitations:\\n\\n1. The HTML editor will remove a number of tags, particularly style and script tags.\\n\\n2. Without changes like the ones we made at GORUCK (described below), all the content will be placed in a single location on the page.\\n\\nAt GORUCK, we needed the ability to inject arbitrary HTML into our page, and to place that content at various specific page locations. To achieve this, we developed the three techniques described below.\\n\\n## <span id=\\\"dropzones\\\">Dropzones</span>\\n\\nLet's say that at the top of your category pages, you want to display a full-width, category-specific, image. And at the bottom of these pages, you want to display a category-specific message or image gallery.\\n\\nOne possibility is to define a custom page for every category. But aside from the work involved to set this up, every time you added or removed a category, you would need to add or remove a custom page from your theme. And of course, it's possible that you would also want control like this on product pages, and on other pages on your storefront.\\n\\nA more general solution we implemented was to create a small set of custom pages: one for categories, one for products, and so on. Each of the custom pages contains a few `div` elements that define *dropzones* for that page.\\n\\nWith these dropzones defined, we can then populate them with dynamic content specific to any instance of the page. Here is an example of a dropzone that places an image gallery at the bottom of a category page:\\n\\n<img src=\\\"https://files.readme.io/14dfb1c-dropzone-bottom.png\\\" alt=\\\"Dropzone at page bottom\\\" height=\\\"100%\\\" width=\\\"100%\\\" style=\\\"border:1px solid #D1D7E0\\\"></span>\\n\\n#### Dropzones HTML\\n\\nThe HTML for a dropzone is simply something like:\\n\\n```\\n<div id=\\\"gr-dropzone-top\\\"></div>\\n```\\n\\n...where the div's `id` defines the dropzone's name.\\n\\nThen, using the BigCommerce control panel's custom HTML editor (in this example, the Categories editor), we place our content inside `div` tags that specify the dropzone where the content should be inserted. Here is a simple example:\\n\\n```\\n<div class=\\\"gr-dropzone\\\" data-gr-zone=\\\"gr-dropzone-top\\\">\\n\\t<p>This content will be placed in a dropzone at the top of the page, because that dropzone has the id matching our data-gr-zone attribute.</p>\\n</div>\\n```\\n\\n#### Dropzones HTML Example\\n\\nHere is an example of some HTML that we actually use:\\n\\n```\\n<div class=\\\"gr-dropzone\\\" data-gr-zone=\\\"gr-dropzone-bottom\\\">\\n    <h3>GORUCK GEAR IN THE FIELD</h3>\\n    <div id=\\\"bv-grid-gallery\\\" data-gr-groups=\\\"goruck-rm-group\\\" data-gr-tags=\\\"gear\\\"></div>\\n</div>\\n```\\n\\nAny content that isn't wrapped in a `div` with the class `gr-dropzone` simply appears at the default location provided by the theme.\\n\\n#### Dropzones JavaScript\\n\\nThe content is moved from the default location to the dropzone by JavaScript we added to the `PageManager` class. In&#160;BigCommerce's Cornerstone base theme, Pixel Union's Merchant theme, and other Stencil themes, `PageManager` is the parent class of all page classes. So, its methods get invoked on every page. This makes it a great place to put code like this, which needs to run every time a page is loaded.\\n\\nWe modified our theme's `PageManager.before` method to invoke a new method named `gr_moveHtmlToDropzones`:\\n\\n```\\n\\tgr_moveHtmlToDropzones () {\\n\\t\\t$(\\\".gr-dropzone\\\").each(function () {\\n\\t\\t\\tconst $this = $(this);\\n\\t\\t\\tconst zoneId = $this.data(\\\"gr-zone\\\");\\n\\t\\t\\tif (zoneId) {\\n\\t\\t\\t\\t$(\\\"#\\\" + zoneId).html($this.html());   // copy the html to where it should be\\n\\t\\t\\t\\t$this.remove();             // remove the html from its temporary location\\n\\t\\t\\t} else {\\n\\t\\t\\t\\tconsole.warn(\\\"PageManager.gr_moveHtmlToDropzones: dropzone has no target.\\\");\\n\\t\\t\\t}\\n\\t\\t});\\n\\t}\\n```\\n\\nFinally, in our .scss file, we set the `.gr-dropzone` class to `display: none`. This prevents the content from appearing on the page in the wrong location before `PageManager` has a chance to move it into the dropzone.\\n\\n\\n## <span id=\\\"tabs\\\">Dynamic Tabs</span>\\n\\nOur Stencil base theme presents information on our product pages in several tabs. We wanted to introduce several new tabs, and to vary the tabs by product category and brand. Additionally, we wanted the ability to store a tab's content in an external file, on our WebDAV or CDN (content delivery network).\\n\\nBy storing content in an external file, we can share identical content across pages, without copying and pasting. Also, changes to the content can be made just once, and be reflected on all our pages.\\n\\nSo we implemented a feature we call Dynamic Tabs. Dynamic Tabs are similar to dropzones, in that they allow you to use the control panel's HTML editor to provide content, while moving it to a specific location on the page. In this case, our content will appear in a tab. \\n\\nIn the example below, we use this technique to place the `RIGHT BY YOU` tab in the fourth position:\\n\\n<img src=\\\"https://files.readme.io/accd11f-dynamic-tab-rby.png\\\" alt=\\\"Dynamic tab &ndash; Right By You\\\" height=\\\"100%\\\" width=\\\"100%\\\" style=\\\"border:1px solid #D1D7E0\\\"></span>\\n \\n#### Dynamic Tabs HTML\\n\\nThere are two versions of the HTML. The first is designed for a tab you want to drop in using a page's own HTML:\\n\\n``` \\n<div class=\\\"gr-tab\\\" data-gr-position=\\\"POSITION\\\" data-gr-title=\\\"TITLE\\\"> \\n     CONTENT \\n</div>\\n```\\n \\nThe second version is designed for a tab that gets its content from an external file:\\n\\n``` \\n<div class=\\\"gr-tab\\\" data-gr-content=\\\"CONTENT URL\\\">\\n</div> \\n```\\n\\nIn this second case, the HTML in that external file must start with the `POSITION` and `TITLE` information: \\n\\n```\\n<input id=\\\"gr-tab-data\\\" type=\\\"hidden\\\" data-gr-position=\\\"POSITION\\\" data-gr-title=\\\"TITLE\\\" /> \\n CONTENT \\n```\\n\\n#### Dynamic Tabs Parameters\\n\\n`POSITION` is a number, which determines where the dynamic tab will be put. For example, a `POSITION` of `3` means that the tab will be placed after the third tab.\\n \\nWe use a `POSITION` of `0` to place a tab ahead of the first tab. If the `POSITION` attribute is omitted, the tab will be placed *after* all the other tabs. (Note that if you add multiple dynamic tabs, any `POSITION` that you specify must account for the previously inserted dynamic tabs.)\\n \\n`TITLE` is the text you want to display as the tab's title. For example: `Our Guarantee`. \\n \\n`CONTENT` is any arbitrary HTML, and is displayed when the user clicks on the tab's title.\\n\\n\\n#### Dynamic Tabs HTML Example\\n\\nTo create the `RIGHT BY YOU` tab in the screenshot above, we added this code to our base theme's `templates/pages/product.html` template:\\n\\n```\\n<!-- GORUCK Customization: pull in a dynamic tab -->\\n  <div class=\\\"gr-tab\\\" data-gr-content=\\\"/content/tabs/dynamicTab1.html?v=14\\\">\\n  </div>\\n```\\n\\nThis tells our code to pull in a file named `dynamicTab1.html`, located in our WebDAV's `/content/tabs/` folder. The querystring is used just to defeat caching.\\n\\nHere are the contents of our `dynamicTab1.html` file:\\n\\n```\\n<input id=\\\"gr-tab-data\\\" type=\\\"hidden\\\" data-gr-position=\\\"3\\\" data-gr-title=\\\"Right By You\\\"/>\\n<div class=\\\"container container-small gr-rightbyyou\\\">\\n  <div style=\\\"display: flex; flex-direction: column\\\">\\n    <div style=\\\"display: flex\\\">\\n      <div>\\n        <img style=\\\"display: block; width: 100px; max-width: 100px; margin-right: 24px\\\" \\n        src=\\\"https://content.goruck.com/2017site/products/free-returns-icon.png\\\" height=\\\"auto\\\"/>\\n      </div>\\n    <div>\\n      <h3 style=\\\"margin-top: 0\\\">Free &amp; Easy Returns</h3>\\n      <p>Don't like it? Send it back for free. Returnable in like-new condition within 30 days and \\n      every order comes with a free return shipping label. Too easy.</p>\\n    </div>\\n  </div>\\n\\n  <div style=\\\"display: flex; margin-top: 12px\\\">\\n    <div>\\n      <img style=\\\"display: block; width: 100px; max-width: 100px; margin-right: 24px\\\" \\n      src=\\\"https://content.goruck.com/2017site/products/challenge-excellence.png\\\" height=\\\"auto\\\"/>\\n    </div>\\n\\n    <div>\\n      <h3 style=\\\"margin-top: 0\\\">Challenge Excellence</h3>\\n      <p>We have two grades, A and F and A- rounds down. Excellence is the standard and please hold us to it, \\n      we want you to love your gear as much as we do.</p>\\n    </div>\\n  </div>\\n\\n  <div style=\\\"display: flex; margin-top: 12px\\\">\\n    <div>\\n      <img style=\\\"display: block; width: 100px; max-width: 100px; margin-right: 24px\\\" \\n      src=\\\"https://content.goruck.com/2017site/products/customer-service-icon.png\\\" height=\\\"auto\\\"/>\\n    </div>\\n      <div>\\n        <h3 style=\\\"margin-top: 0\\\">Do Right By People</h3>\\n        <p>Our goal is to run a company our grandfathers would be proud of. And the central tenet \\n        &mdash; an oldie but a goodie &mdash; is that we do whatever it takes to do right by people.\\n        Contact us at <a href=\\\"https://goruck.zendesk.com/hc/en-us/requests/new\\\" target=\\\"_blank\\\">\\n        team:::at:::goruck.com</a> with any questions and we'll get back to you ASAP.</p>\\n      </div>\\n    </div>\\n  </div>\\n</div>\\n```\\n\\nHere is the custom tab rendered by the above HTML:\\n\\n<img src=\\\"https://files.readme.io/be338d2-rby-panel.png\\\" alt=\\\"Dynamic tab &ndash; Rendered custom tab\\\" height=\\\"100%\\\" width=\\\"100%\\\" style=\\\"border:1px solid #D1D7E0\\\"></span>\\n\\n#### Dynamic Tabs JavaScript\\n\\nAgain, the JavaScript code to implement Dynamic Tabs is invoked in the `PageManager` class' `before` method. The Dynamic Tabs code is more complex, and it relies on other classes we wrote to get content from the external server and cache it in the browser.\\n\\nNevertheless, none of it is rocket science. The three classes involved are 250 lines of code. Interested readers are invited to [contact me](https://forum.bigcommerce.com/s/profile/0051B00000CftknQAB) via the [BigCommerce Developers forum](https://forum.bigcommerce.com/s/group/0F913000000HLjECAW) for more information about the implementation.\\n\\n\\n## <span id=\\\"snippets\\\">Snippets</span>\\n\\nSnippets are similar to Dynamic Tabs, in that they allow you to use the BigCommerce control panel's HTML editor to provide content, but pull it from a separate file. This allows you to share common content across multiple pages.\\n\\nAlso, because the control panel's HTML editor strips out stylesheets, this is a good way to provide page-specific styles for a page.\\n\\nWe use snippets at GORUCK to display our sizing charts, as shown below. This makes sense since because we have a handful of charts that need to be shared across many products, so we don't want to copy and paste each chart for every product that needs it.\\n\\n<img src=\\\"https://files.readme.io/57aadb6-dynamic-tab-team-rwbsnippet-chart.png\\\" alt=\\\"Snippet &ndash; Sizing chart\\\" height=\\\"100%\\\" width=\\\"100%\\\" style=\\\"border:1px solid #D1D7E0\\\"></span>\\n\\n#### Snippets HTML\\n\\nHere is the format of the HTML that needs to placed on each page that uses the snippet: \\n\\n```\\n<div class=\\\"gr-snippet\\\" data-gr-content=\\\"CONTENT URL\\\">\\n     <em>Loading...</em>\\n</div> \\n```\\n\\nThe external file can contain any arbitrary HTML and CSS, and the styled HTML is displayed in the page location where the `gr-snippet` div is located.  \\n\\n#### Snippets JavaScript\\n\\nLike Dropzones and Dynamic Tabs, the Snippets code is invoked in `PageManager`'s `before` method. Snippets adds just another 50 lines of JavaScript code to the theme, also relying on the same code that Dynamic Tabs uses to get the external file and cache it in the browser.\\n\\n## Recap\\n\\nAt GORUCK, we've developed a number of techniques that allow us to separate our content from our theme. These techniques have proved valuable to us, because they allow us to: \\n\\n* Keep our content development and software development workflows separate.\\n* Reduce modifications to our theme, which simplifies merging updates from our theme provider.\\n* Share content across multiple pages.\\n* Tailor our content based on product category and brand.\"\n}\n[/block]","excerpt":"","slug":"dynamic-content","type":"basic","title":"Dynamic Content Rendering on Stencil Storefronts"}

Dynamic Content Rendering on Stencil Storefronts


[block:html] { "html": "<!-- For screenshots: There's a row of Dynamic Tabs above a sizing-chart Snippet on this page: https://www.goruck.com/hoodie-eagle/ \n...and a bottom Dropzone on this page: https://www.goruck.com/collections/shop-all/ -->" } [/block] This page outlines several techniques for enhancing Stencil themes with dynamic content injection. It covers: * [Why Dynamic Content?: Dropzones, Dynamic Tabs, and Snippets](#overview) * [Dropzones](#dropzones) * [Dynamic Tabs](#tabs) * [Snippets](#snippets) We're gratefully sharing techniques devised by Ken Utting, Web Developer for BigCommerce client [goruck.com](https://www.goruck.com/): <a name="overview"></a> [block:callout] { "type": "info", "title": "Why Dynamic Content?: Dropzones, Dynamic Tabs, and Snippets", "body": "At GORUCK, we've customized our Stencil theme ([Merchant](https://www.bigcommerce.com/theme/merchant-light/)) to provide several ways to update our site content without requiring changes to the theme itself. This allows our content folks to make changes to our theme without having to wait on our software developers.\n\nAlso, by pushing content out of the theme, these techniques reduce the differences between our customized theme and the out-of-the-box (base) theme – which makes it easier to [integrate ongoing updates](/docs/theme-updates-sync#isolate) into our theme. Finally, these techniques allow us share identical content across pages without copying and pasting.\n\nThree techniques in particular have proven useful to us. We call them [Dropzones](#dropzones), [Dynamic Tabs](#tabs), and [Snippets](#snippets). There is nothing particularly special to GORUCK about these techniques, so there is no reason you can't adopt them for your own store/theme.\n\n#### Building on the Control Panel\n\nThe BigCommerce control panel provides an HTML editor where you can enter custom content for Products, Categories, and custom static pages (`Storefront` > `Web Pages`). But we encountered these limitations:\n\n1. The HTML editor will remove a number of tags, particularly style and script tags.\n\n2. Without changes like the ones we made at GORUCK (described below), all the content will be placed in a single location on the page.\n\nAt GORUCK, we needed the ability to inject arbitrary HTML into our page, and to place that content at various specific page locations. To achieve this, we developed the three techniques described below.\n\n## <span id=\"dropzones\">Dropzones</span>\n\nLet's say that at the top of your category pages, you want to display a full-width, category-specific, image. And at the bottom of these pages, you want to display a category-specific message or image gallery.\n\nOne possibility is to define a custom page for every category. But aside from the work involved to set this up, every time you added or removed a category, you would need to add or remove a custom page from your theme. And of course, it's possible that you would also want control like this on product pages, and on other pages on your storefront.\n\nA more general solution we implemented was to create a small set of custom pages: one for categories, one for products, and so on. Each of the custom pages contains a few `div` elements that define *dropzones* for that page.\n\nWith these dropzones defined, we can then populate them with dynamic content specific to any instance of the page. Here is an example of a dropzone that places an image gallery at the bottom of a category page:\n\n<img src=\"https://files.readme.io/14dfb1c-dropzone-bottom.png\" alt=\"Dropzone at page bottom\" height=\"100%\" width=\"100%\" style=\"border:1px solid #D1D7E0\"></span>\n\n#### Dropzones HTML\n\nThe HTML for a dropzone is simply something like:\n\n```\n<div id=\"gr-dropzone-top\"></div>\n```\n\n...where the div's `id` defines the dropzone's name.\n\nThen, using the BigCommerce control panel's custom HTML editor (in this example, the Categories editor), we place our content inside `div` tags that specify the dropzone where the content should be inserted. Here is a simple example:\n\n```\n<div class=\"gr-dropzone\" data-gr-zone=\"gr-dropzone-top\">\n\t<p>This content will be placed in a dropzone at the top of the page, because that dropzone has the id matching our data-gr-zone attribute.</p>\n</div>\n```\n\n#### Dropzones HTML Example\n\nHere is an example of some HTML that we actually use:\n\n```\n<div class=\"gr-dropzone\" data-gr-zone=\"gr-dropzone-bottom\">\n <h3>GORUCK GEAR IN THE FIELD</h3>\n <div id=\"bv-grid-gallery\" data-gr-groups=\"goruck-rm-group\" data-gr-tags=\"gear\"></div>\n</div>\n```\n\nAny content that isn't wrapped in a `div` with the class `gr-dropzone` simply appears at the default location provided by the theme.\n\n#### Dropzones JavaScript\n\nThe content is moved from the default location to the dropzone by JavaScript we added to the `PageManager` class. In&#160;BigCommerce's Cornerstone base theme, Pixel Union's Merchant theme, and other Stencil themes, `PageManager` is the parent class of all page classes. So, its methods get invoked on every page. This makes it a great place to put code like this, which needs to run every time a page is loaded.\n\nWe modified our theme's `PageManager.before` method to invoke a new method named `gr_moveHtmlToDropzones`:\n\n```\n\tgr_moveHtmlToDropzones () {\n\t\t$(\".gr-dropzone\").each(function () {\n\t\t\tconst $this = $(this);\n\t\t\tconst zoneId = $this.data(\"gr-zone\");\n\t\t\tif (zoneId) {\n\t\t\t\t$(\"#\" + zoneId).html($this.html()); // copy the html to where it should be\n\t\t\t\t$this.remove(); // remove the html from its temporary location\n\t\t\t} else {\n\t\t\t\tconsole.warn(\"PageManager.gr_moveHtmlToDropzones: dropzone has no target.\");\n\t\t\t}\n\t\t});\n\t}\n```\n\nFinally, in our .scss file, we set the `.gr-dropzone` class to `display: none`. This prevents the content from appearing on the page in the wrong location before `PageManager` has a chance to move it into the dropzone.\n\n\n## <span id=\"tabs\">Dynamic Tabs</span>\n\nOur Stencil base theme presents information on our product pages in several tabs. We wanted to introduce several new tabs, and to vary the tabs by product category and brand. Additionally, we wanted the ability to store a tab's content in an external file, on our WebDAV or CDN (content delivery network).\n\nBy storing content in an external file, we can share identical content across pages, without copying and pasting. Also, changes to the content can be made just once, and be reflected on all our pages.\n\nSo we implemented a feature we call Dynamic Tabs. Dynamic Tabs are similar to dropzones, in that they allow you to use the control panel's HTML editor to provide content, while moving it to a specific location on the page. In this case, our content will appear in a tab. \n\nIn the example below, we use this technique to place the `RIGHT BY YOU` tab in the fourth position:\n\n<img src=\"https://files.readme.io/accd11f-dynamic-tab-rby.png\" alt=\"Dynamic tab &ndash; Right By You\" height=\"100%\" width=\"100%\" style=\"border:1px solid #D1D7E0\"></span>\n \n#### Dynamic Tabs HTML\n\nThere are two versions of the HTML. The first is designed for a tab you want to drop in using a page's own HTML:\n\n``` \n<div class=\"gr-tab\" data-gr-position=\"POSITION\" data-gr-title=\"TITLE\"> \n CONTENT \n</div>\n```\n \nThe second version is designed for a tab that gets its content from an external file:\n\n``` \n<div class=\"gr-tab\" data-gr-content=\"CONTENT URL\">\n</div> \n```\n\nIn this second case, the HTML in that external file must start with the `POSITION` and `TITLE` information: \n\n```\n<input id=\"gr-tab-data\" type=\"hidden\" data-gr-position=\"POSITION\" data-gr-title=\"TITLE\" /> \n CONTENT \n```\n\n#### Dynamic Tabs Parameters\n\n`POSITION` is a number, which determines where the dynamic tab will be put. For example, a `POSITION` of `3` means that the tab will be placed after the third tab.\n \nWe use a `POSITION` of `0` to place a tab ahead of the first tab. If the `POSITION` attribute is omitted, the tab will be placed *after* all the other tabs. (Note that if you add multiple dynamic tabs, any `POSITION` that you specify must account for the previously inserted dynamic tabs.)\n \n`TITLE` is the text you want to display as the tab's title. For example: `Our Guarantee`. \n \n`CONTENT` is any arbitrary HTML, and is displayed when the user clicks on the tab's title.\n\n\n#### Dynamic Tabs HTML Example\n\nTo create the `RIGHT BY YOU` tab in the screenshot above, we added this code to our base theme's `templates/pages/product.html` template:\n\n```\n<!-- GORUCK Customization: pull in a dynamic tab -->\n <div class=\"gr-tab\" data-gr-content=\"/content/tabs/dynamicTab1.html?v=14\">\n </div>\n```\n\nThis tells our code to pull in a file named `dynamicTab1.html`, located in our WebDAV's `/content/tabs/` folder. The querystring is used just to defeat caching.\n\nHere are the contents of our `dynamicTab1.html` file:\n\n```\n<input id=\"gr-tab-data\" type=\"hidden\" data-gr-position=\"3\" data-gr-title=\"Right By You\"/>\n<div class=\"container container-small gr-rightbyyou\">\n <div style=\"display: flex; flex-direction: column\">\n <div style=\"display: flex\">\n <div>\n <img style=\"display: block; width: 100px; max-width: 100px; margin-right: 24px\" \n src=\"https://content.goruck.com/2017site/products/free-returns-icon.png\" height=\"auto\"/>\n </div>\n <div>\n <h3 style=\"margin-top: 0\">Free &amp; Easy Returns</h3>\n <p>Don't like it? Send it back for free. Returnable in like-new condition within 30 days and \n every order comes with a free return shipping label. Too easy.</p>\n </div>\n </div>\n\n <div style=\"display: flex; margin-top: 12px\">\n <div>\n <img style=\"display: block; width: 100px; max-width: 100px; margin-right: 24px\" \n src=\"https://content.goruck.com/2017site/products/challenge-excellence.png\" height=\"auto\"/>\n </div>\n\n <div>\n <h3 style=\"margin-top: 0\">Challenge Excellence</h3>\n <p>We have two grades, A and F and A- rounds down. Excellence is the standard and please hold us to it, \n we want you to love your gear as much as we do.</p>\n </div>\n </div>\n\n <div style=\"display: flex; margin-top: 12px\">\n <div>\n <img style=\"display: block; width: 100px; max-width: 100px; margin-right: 24px\" \n src=\"https://content.goruck.com/2017site/products/customer-service-icon.png\" height=\"auto\"/>\n </div>\n <div>\n <h3 style=\"margin-top: 0\">Do Right By People</h3>\n <p>Our goal is to run a company our grandfathers would be proud of. And the central tenet \n &mdash; an oldie but a goodie &mdash; is that we do whatever it takes to do right by people.\n Contact us at <a href=\"https://goruck.zendesk.com/hc/en-us/requests/new\" target=\"_blank\">\n team@goruck.com</a> with any questions and we'll get back to you ASAP.</p>\n </div>\n </div>\n </div>\n</div>\n```\n\nHere is the custom tab rendered by the above HTML:\n\n<img src=\"https://files.readme.io/be338d2-rby-panel.png\" alt=\"Dynamic tab &ndash; Rendered custom tab\" height=\"100%\" width=\"100%\" style=\"border:1px solid #D1D7E0\"></span>\n\n#### Dynamic Tabs JavaScript\n\nAgain, the JavaScript code to implement Dynamic Tabs is invoked in the `PageManager` class' `before` method. The Dynamic Tabs code is more complex, and it relies on other classes we wrote to get content from the external server and cache it in the browser.\n\nNevertheless, none of it is rocket science. The three classes involved are 250 lines of code. Interested readers are invited to [contact me](https://forum.bigcommerce.com/s/profile/0051B00000CftknQAB) via the [BigCommerce Developers forum](https://forum.bigcommerce.com/s/group/0F913000000HLjECAW) for more information about the implementation.\n\n\n## <span id=\"snippets\">Snippets</span>\n\nSnippets are similar to Dynamic Tabs, in that they allow you to use the BigCommerce control panel's HTML editor to provide content, but pull it from a separate file. This allows you to share common content across multiple pages.\n\nAlso, because the control panel's HTML editor strips out stylesheets, this is a good way to provide page-specific styles for a page.\n\nWe use snippets at GORUCK to display our sizing charts, as shown below. This makes sense since because we have a handful of charts that need to be shared across many products, so we don't want to copy and paste each chart for every product that needs it.\n\n<img src=\"https://files.readme.io/57aadb6-dynamic-tab-team-rwbsnippet-chart.png\" alt=\"Snippet &ndash; Sizing chart\" height=\"100%\" width=\"100%\" style=\"border:1px solid #D1D7E0\"></span>\n\n#### Snippets HTML\n\nHere is the format of the HTML that needs to placed on each page that uses the snippet: \n\n```\n<div class=\"gr-snippet\" data-gr-content=\"CONTENT URL\">\n <em>Loading...</em>\n</div> \n```\n\nThe external file can contain any arbitrary HTML and CSS, and the styled HTML is displayed in the page location where the `gr-snippet` div is located. \n\n#### Snippets JavaScript\n\nLike Dropzones and Dynamic Tabs, the Snippets code is invoked in `PageManager`'s `before` method. Snippets adds just another 50 lines of JavaScript code to the theme, also relying on the same code that Dynamic Tabs uses to get the external file and cache it in the browser.\n\n## Recap\n\nAt GORUCK, we've developed a number of techniques that allow us to separate our content from our theme. These techniques have proved valuable to us, because they allow us to: \n\n* Keep our content development and software development workflows separate.\n* Reduce modifications to our theme, which simplifies merging updates from our theme provider.\n* Share content across multiple pages.\n* Tailor our content based on product category and brand." } [/block]