Skip to main content

The Anatomy of a Shared Partial

Overview

Most of our components are available as shared partials that can be referenced when building a CleanSlate theme. The developer can add them directly to their own theme, or they can be called via “slots" when using the Super Template. But what if you want to get fancy and create your own partial, based on the same concepts that are used to create one of our shared partials?

In order to help you understand how our shared partials work, we have added comments to the code in each partial. We realize, however, that this may not be enough. That’s why we’ve also created this tutorial. Let’s take a look at an example of a shared partial, then break it down. Here is the _wvu-hero.html partial:

<r:comment><!-- Define a base name for this component. We can use this later to dynamically create editable region names -->&rt;/r:comment>
<r:set_var name="baseComponentName" value="hero" />

<r:comment><!-- Pull in component name, instance number, scope, limit, featurettes style, etc. that determine how the component will function. This also defines editable region names for component classes, featurettes classes, etc. --></r:comment>
<r:partial name="includes/wvu-component-variables" theme="University Relations: WVU Design System" />

<r:comment><!-- Define editable region names using our component name (base component name + instance number) within a namespaced label. --></r:comment>
<r:set_var name="componentHeader">wvu-<r:var name="componentName" />__header</r:set_var>
<r:set_var name="componentMain">wvu-<r:var name="componentName" />__main</r:set_var>
<r:set_var name="headerClasses">wvu-<r:var name="componentName" />-header-classes</r:set_var>

<r:comment><!-- Assign utility classes to assign to this components’s stylable elements. These will be applied by default if the content editor does not apply her own. --></r:comment>
<r:content_for name="{$defaultComponentClasses}">bg-dark text-white wvu-bg-position-center wvu-bg-size-cover wvu-bg-vignetting</r:content_for>
<r:content_for name="{$defaultHeaderClasses}">display-1 wvu-shout wvu-slash</r:content_for>

<r:comment><-- Add an openin markup tag. This is used by the demo site to auto-generate code that the user can copy into their own theme. --></r:comment>
<r:comment><!-- This component’s outer container also contains utilities for evaluating whether the component should get a section or a main tag, what classes to apply to the outer container, and a background styler, defined by uploading an image and labeling it with the page slug and component name. --></r:comment>
<!-- Markup --><<r:partial name="utilities/wvu-is-main-checker" theme="University Relations: WVU Design System" /> aria-labelledby="<r:var name="componentName" />-label" class="jumbotron jumbotron-fluid mb-0 wvu-overflow-hidden wvu-bg-size-cover <r:partial name="utilities/wvu-component-classes-checker" theme="University Relations: WVU Design System" />" <r:partial name="utilities/wvu-bg-styler" theme="University Relations: WVU Design System" />>
  <div class="container position-relative wvu-z-index-content">
    <div class="row py-5<r:if v1="{$hero_text_alignment}" v2="1" operator="="> justify-content-end</r:if>">
      <div class="col col-md-6 <r:if v1="{$componentAlign}" v2="right" op="=">ml-md-auto</r:if><r:if v1="{$componentAlign}" v2="middle" op="=">mx-md-auto</r:if>">
      
        <r:comment><!-- This is where you can add utility classes that will apply to the hero’s heading. --></r:comment>
        <r:edit_mode_only>
          <small class="wvu-z-index-content d-block mb-2 text-left text-muted p-1 bg-wvu-neutral--dark-gray">Header classes:
            <pre class="mb-0 text-white"><r:editable_region name="{$headerClasses}" type="simple" /></pre>
            <strong class="text-muted">Default classes:</strong> <pre class="mb-0 text-muted"><r:yield name="{$defaultHeaderClasses}"><r:content /></r:yield></pre>
          </small>
        </r:edit_mode_only>
        
        <r:comment><!-- For the h1, apply an ID that will tell screanreaders to use this element as the label for the section. --></r:comment>
        <h1 id="<r:var name="componentName" />-label" class="<r:page:if_has_content_for region="{$headerClasses}"><r:page:content name="{$headerClasses}" /></r:page:if_has_content_for><r:page:unless_has_content_for region="{$headerClasses}"><r:yield name="{$defaultHeaderClasses}"><r:content /></r:yield></r:page:unless_has_content_for>">
          <r:editable_region name="{$componentHeader}" scope="{$componentScope}" type="simple">
            It Starts Now.
          </r:editable_region>
        </h1>
        
        <r:comment><!-- Use the editable region name for th main section of the hero, which you defined above. --></r:comment>
        <r:editable_region name="{$componentMain}" scope="{$componentScope}">
          <p class="lead py-2">This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.</p>
          <a class="btn btn-primary btn-lg" href="#" role="button">Call to Action</a>
        </r:editable_region>
      </div>
    </div>
  </div>
  
  <r:comment><!-- A utility to decide whether to add a closing main or section tag. --></r:comment>
</<r:partial name="utilities/wvu-is-main-checker" theme="University Relations: WVU Design System" />><!-- End markup --><r:comment><!-- Closing main/section tag is the closing markup tag. This is used by the demo site to auto-generate code that the user can copy into their own theme. --></r:comment>

<r:comment><!-- Pull in partial that contains the component styler. This lets the user add classes to the component using the CleanSlate editor. --></r:comment>
<r:partial name="includes/wvu-component-footer" theme="University Relations: WVU Design System" />

General Structure

The general structure is as follows:

  1. Define a base component name. This will be used when defining editable region names that are unique to the component.
  2. Establish a set of variables that map to how the component functions. The developer can then use these variables to pass values to the component to make it function how they want e.g. tell a featurette to sort by page title. This can be done either directly in a template or via “slots” in the Super Theme.
  3. Set your editable region names. This is done dynamically using the base component name and an instance number. It allows the component to be used more than once on the same page.
  4. Set default content. Certain editable regions should have default content that can be overwritten by the content editor. If the content editor chooses not to overwrite them, no harm done. This is mainly used to define utility classes that get added to the component styler.
  5. Include a footer. This adds the component styler to each component, which can be used to inject utility classes to various elements.
  6. Include utility partials. This lets you perform repetitive tasks across multiple components, for example styling a background or making certain HTML elements conditional e.g. using a <main> tag versus a <section> tag.
  7. You have the option to do Component Inception i.e. add components to other components.

Define a Base Component Name

Define a base component name. This will be used later on, when defining editable region names that are unique to the component. It looks like this:

<r:set_var name="baseComponentName" value="hero" />

Establish Variables That Map to Component Functionality

Each partial can be configured by passing values to a number of standard variables. These values cause your partial to function differently, based on what you need it to do. For example, if you are using a featurettes pattern, which loops through pages and grabs certain content to display, you might want to set the sort_order to make the items display in the order you want.

But how do variables get pulled into each partial? Each partial contains a _wvu-component-variables.html include that defines what variables can be accepted, along with a default value for each. You call the _wvu-component-variables.html include like this:

<r:partial name="includes/wvu-component-variables" theme="University Relations: WVU Design System" />

The _wvu-component-variables.html include itself looks like this:

<r:comment><!-- Pull in instance number from a given “slot” if using Super Theme, else set it to “1” (this can also be overritten in your template if you need more than one instance of your component). We need to define an instance number in case we want to use the component more than once on a page. --></r:comment>
<r:set_var name="componentInstance" value="{$instanceNumber}" default="1" />

<r:comment><!-- Pull in scope from “slot” if using Super Theme, else set it to “page”. Can also be overwritten in template (the same goes for any other variables that accept values from a “slot”). --></r:comment>
<r:set_var name="componentScope" value="{$scope}" default="page" />

<r:comment><!-- Unique name of component (combines base component name, which is defined in the component partial, with an instance number). We can use this when creating unique editable region names for our component, or for assigning a label to set as a background image to our component. --></r:comment>
<r:set_var name="componentName">
  <r:var name="baseComponentName" />-<r:var name="componentInstance" />
</r:set_var>

<r:comment><!-- Pull in value from an “Is Main” checkbox in Super Theme. Gets used by a wvu-is-main-checker utility partial, which toggles between secion and main tags on the outer container of a component’s HTML. --></r:comment>
<r:set_var name="componentIsMain" value="{$isMain}" default="false" />

<r:comment><!-- Pull in value from an “Randomize” checkbox in Super Theme. Gets used by a featurettes component to randomize items when listing them. --></r:comment>
<r:set_var name="componentIsRandom" value="{$isRandom}" default="false" />

<r:comment><!-- Pull in value from “Featurettes Style” dropdown in Super Theme. Gets used to determine which partial to use with a featurette (default, profiles, blog articles, etc.). --></r:comment>
<r:set_var name="componentFeaturettesStyle" value="{$featurettesStyle}" default="default" />

<r:comment><!-- Pull in value from “Featurettes ID” text box in Super Theme. Gets used by a featurette to know what partent to start from when cycling through children from which to grab and display content from. --></r:comment>
<r:set_var name="componentFeaturettesID" value="{$featurettesID}" />

<r:comment><!-- Pull in value from Alignment dropdown in Super Theme. Gets used by the hero component to set text to the left, center, or right. --></r:comment>
<r:set_var name="componentAlign" value="{$align}" />

<r:comment><!-- Pull in value from “Where to display” dropdown in Super Theme. Gets used by certain components that can accept other components embedded within them. In these components, we loop through all slots and if the display context matches, we pull in that component. --></r:comment>
<r:set_var name="componentDisplayContext" value="{$whereToDisplay}" default="as_full_width_block" />

<r:comment><!-- Pull in value from a “Limit” text box in Super Theme. Gets used to define how many items are displayed in a featurettes component. --></r:comment>
<r:set_var name="componentLimit" value="{$limit}" default="4" />

<r:comment><!-- Pull in value from a “Loop By” dropdown in Super Theme. Gets used by a featurettes partial to know what criteria should be evaluated when displaying items (sort order, slug, name, etc.). --></r:comment>
<r:set_var name="componentLoopBy" value="{$loopBy}" default="sort_order" />

<r:comment><!-- Pull in value from a “Loop Labels Match” dropdown in Super Theme. Gets used by a featurettes partial to know what labels to evaluate when displaying items. --></r:comment>
<r:set_var name="componentLoopLabelsMatch" value="{$loopLabelsMatch}" default="all" />

<r:comment><!-- Pull in value from a “Loop Order” dropdown in Super Theme. Gets used by a featurettes partial to know what criteria whether to display items in either ascending or descending order. --></r:comment>
<r:set_var name="componentLoopOrder" value="{$loopOrder}" default="asc" />

<r:comment><!-- Labels that will allow us to assign a background image to the component. --></r:comment>
<r:set_var name="bgurl">
  <r:page:slug />-<r:var name="componentName" />-background
</r:set_var>

<r:comment><!-- Name of editable region where user can enter classes that will apply to the component’t outer container. --></r:comment>
<r:set_var name="componentClasses">
  wvu-<r:var name="componentName" />-classes
</r:set_var>

<r:comment><!-- Name of editable region containing classes that get applied to a component’s outer container if no “component classes” are provided by the content editor. --></r:comment>
<r:set_var name="defaultComponentClasses">
  wvu-<r:var name="componentName" />-default-component-classes
</r:set_var>

<r:comment><!-- Name of editable region containing classes that get applied to a component’s header if no “component header classes” are provided by the content editor. The editable region for the component header classes is defined in the component partial. --></r:comment>
<r:set_var name="defaultHeaderClasses">
  wvu-<r:var name="componentName" />-default-header-classes
</r:set_var>

<r:comment><!-- Name of editable region containing classes that get applied to the outer container of a featurette’s items. --></r:comment>
<r:set_var name="itemClasses">
  wvu-<r:var name="componentName" />-item-classes
</r:set_var>

<r:comment><!-- Name of editable region containing classes that get applied to the header of a featurette’s items. --></r:comment>
<r:set_var name="itemHeaderClasses">
  wvu-<r:var name="componentName" />-item-header-classes
</r:set_var>

<r:comment><!-- Name of editable region containing classes that get applied to the body text of a featurette’s items. --></r:comment>
<r:set_var name="itemBodyClasses">
  wvu-<r:var name="componentName" />-item-body-classes
</r:set_var>

<r:comment><!-- Name of editable region containing classes that get applied to the outer container of a featurette’s items if no “item classes” are provided by the content editor. --></r:comment>
<r:set_var name="defaultItemClasses">
  wvu-<r:var name="componentName" />-default-item-classes
</r:set_var>

<r:comment><!-- Name of editable region containing classes that get applied to the header of a featurette’s items if no “item header classes” are provided by the content editor. --></r:comment>
<r:set_var name="defaultItemHeaderClasses">
  wvu-<r:var name="componentName" />-default-item-header-classes
</r:set_var>

<r:comment><!-- Name of editable region containing classes that get applied to the body text of a featurette’s items if no “item body classes” are provided by the content editor. --></r:comment>
<r:set_var name="defaultItemBodyClasses">
  wvu-<r:var name="componentName" />-default-item-body-classes
</r:set_var>

<r:comment><!-- Name of editable region that lets the user define the button text that gets applied to items in a featurette. --></r:comment>
<r:set_var name="componentReadMoreButtonText">
  wvu-<r:var name="componentName" />-button-text
</r:set_var>

You can see where we define the component name on line 7, which is the base component name i.e. wvu-hero, along with an componentInstance (1, 2, 3). So the component name of the first instance of a hero on a page would be wvu-hero-1. Here is what it looks like when you define the componentInstance variable:

<r:set_var name="componentInstance" value="{$instanceNumber}" default="1" />

In the above example, $instanceNumber is what you would pass in when referencing the shared partial, or set in the Super Template via slots. The variable componentInstance can then be used elsewhere, for example when defining unique editable region names. This is useful if you want to use the component more than once on a page (more on this in the following section).

There are other editable region names that are defined in our _wvu-component-variables include. For example, we might want to dynamically inject classes on certain elements when the user adds those classes to an editable region in the CleanSlate editor. This is how the component styler works. The editable region names for these classes are defined in the variables partial as well. The regions themselves are contained in the _wvu-component-footer.html (more on this below).

Set Editable Region Names

Now that we have defined our variables, including our component name (which, recall, is the base component name, plus an instance number), we can use them to create unique editable region names. Why would we do this? Because we might want to have multiple instances of the same component on the same page. This could be a problem if our component contains editable regions, since you can’t have multiple instances of the same editable region name on the same page without the content in the last instance overwriting all previous instances.

Here is how we define unique editable region names in our _wvu-hero.html partial:

<r:set_var name="componentHeader">wvu-<r:var name="componentName" />__header</r:set_var>
<r:set_var name="componentMain">wvu-<r:var name="componentName" />__main</r:set_var></code>

This gets us two editable region names, wvu-hero-1__header and wvu-hero-1__main, assuming our instance number is 1. If we used another instance of the hero component, with an instance number of 2, then it’s editable region names would be wvu-hero-2__header and wvu-hero-2__main.

Repeat this for as many editable regions you need.

Set Default Content

For some editable regions, we want to set certain content by default. This is useful for our component styler, which allows a content editor to add classes to an element’s outer container. You’d want some classes to display by default, then allow the user to overwrite them if they want the component to look differently. Here is how we define default content for our outer container:

<r:content_for name="{$defaultComponentClasses}">bg-dark text-white wvu-bg-position-center wvu-bg-size-cover wvu-bg-vignetting</r:content_for>

This default content will be displayed whenever you create an editable region called {$defaultComponentClasses}. In this case, we create this region in our wvu-component-footer include. It looks like this when we call it:

<r:yield name="{$defaultItemBodyClasses}">
  <strong>Default classes:>/strong> <r:content />
</r:yield>

Include a Footer

Each component has a footer. The footer contains our component styler. You call the footer at the end of the file like this:

<r:partial name="includes/wvu-component-footer" theme="University Relations: WVU Design System" />

Check out the code for the footer partial if you want to see what’s in it.

Include Utilities

Utilities are partials that contain code that perform repetitive functions used across multiple components. For example, we have a utility that checks whether the component should have a <section> or <main> tag as its outer container. This gets called at both the beginning and end of the component, where the opening <section>or <main> tags would exist in your HTML, as well as at the end of your component, where the </section> or </main>tags would exist in your HTML. We have a utility that checks to see what classes we should add to the component’s outer container. We have a background styler. We have a background styler. Here is what it looks like when we call all three in our outer container’s HTML:

<<r:partial name="utilities/wvu-is-main-checker" theme="University Relations: WVU Design System" /> aria-labelledby="<r:var name="componentName" />-label" class="jumbotron jumbotron-fluid mb-0 wvu-overflow-hidden wvu-bg-size-cover <r:partial name="utilities/wvu-component-classes-checker" theme="University Relations: WVU Design System" />" <r:partial name="utilities/wvu-bg-styler" theme="University Relations: WVU Design System" />>

There is no need to show all of the utilities here. But here is what the _wvu-is-main-checker.html looks like, for example:

<r:if v1="{$componentIsMain}" v2="1" op="=">main</r:if><r:if v1="{$componentIsMain}" v2="1" op="!=">section</r:if>

We also have a utility that checks to see whether the headers of featurette items should be an <h2> or <h3> element. This gets called wherever the <h2> or <h3> tag would go in your HTML. You can see all of our utilities in the views/utilities folder in your theme.

The Rest

The rest of the partial is no different than what CleanSlate developers are already used to doing. Just add radius tags where appropriate. See the CleanSlate CMS documentation for details.

Component Inception

For Super Theme, we can dynamically add certain components within other components. For example, we might want to add a profiles component to a sidebar, or a featurettes component to a back page content region. Check out our tutorial on Component Inception. Here is what the code looks like when you want to perform component inception in your template (in this case, a wvu-backpage component):

<r:partial name="includes/wvu-component-variables-temp" theme="University Relations: WVU Design System" />
<r:set_var name="componentDisplayContext" value="{$componentMain}" />
<r:partial name="utilities/wvu-slots" theme="University Relations: WVU Design System" />
<r:partial name="includes/wvu-component-variables-pop" theme="University Relations: WVU Design System" />

On line 1, we call a partial that temporarily stores the values we passed into the variables of our parent component. We need to do this because, when we incept a new partial inside of another, the values stored in the child partial’s variables will overwrite those of the parent. We don’t want this, since we might need to reference the values stored in the parent’s variables after we incept our new component(s). Here is what the wvu-component-variables-temp partial looks like:

<r:set_var name="componentBaseComponentNameTemp" value="{$baseComponentName}" />
<r:set_var name="componentInstanceTemp" value="{$componentInstance}" />
<r:set_var name="componentScopeTemp" value="{$componentScope}" />
<r:set_var name="componentNameTemp" value="{$componentName}" />
<r:set_var name="bgurlTemp" value="{$bgurl}" />
<r:set_var name="componentClassesTemp" value="{$componentClasses}" />
<r:set_var name="defaultComponentClassesTemp" value="{$defaultComponentClasses}" />
<r:set_var name="defaultHeaderClassesTemp" value="{$defaultHeaderClasses}" />
<r:set_var name="componentIsMainTemp" value="{$componentIsMain}" />
<r:set_var name="componentIsRandomTemp" value="{$componentIsRandom}" />
<r:set_var name="componentHasSubnavTemp" value="{$componentHasSubnav}" />
<r:set_var name="componentFeaturettesStyleTemp" value="{$componentFeaturettesStyle}" />
<r:set_var name="componentFeaturettesIDTemp" value="{$componentFeaturettesID}" />
<r:set_var name="componentAlignTemp" value="{$componentAlign}" />
<r:set_var name="componentDisplayContextTemp" value="{$componentDisplayContext}" />
<r:set_var name="componentLimitTemp" value="{$componentLimit}" />
<r:set_var name="componentLoopByTemp" value="{$componentLoopBy}" />
<r:set_var name="componentPostscriptTemp" value="{$componentPostscript}" />
<r:set_var name="componentPostscriptTemp" value="{$componentPostscript}" />
<r:set_var name="componentClassesTemp" value="{$componentClasses}" />
<r:set_var name="defaultComponentClassesTemp" value="{$defaultComponentClasses}" />

On line 2, we define the context i.e. the name of the target that we will set on our incepted component. This will be used when we call our “slots” partial on line 3. The slots partial loops through slots in a page using Super Theme, looks for any slot that contains the a matching display context (in this case wvu-backpage), then inserts the component.

On line 3, we call a wvu-slots partial. This is how Super Theme inserts partials into a template. For more about slots, see our tutorial on Using Slots with Super Template. The wvu-slots partial will insert a component that targets this particular parent component.

On line 4, we call a partial that “pops” the temporarily stored values back into the parent’s variables. At that point it is like nothing changed within the parent component, and we can carry on as before. Here is what the wvu-component-variables-pop component looks like:

<r:set_var name="baseComponentName" value="{$componentBaseComponentNameTemp}" />
<r:set_var name="componentInstance" value="{$componentInstanceTemp}" />
<r:set_var name="componentScope" value="{$componentScopeTemp}" />
<r:set_var name="componentName" value="{$componentNameTemp}" />
<r:set_var name="bgurl" value="{$bgurlTemp}" />
<r:set_var name="componentClasses" value="{$componentClassesTemp}" />
<r:set_var name="defaultComponentClasses" value="{$defaultComponentClassesTemp}" />
<r:set_var name="defaultHeaderClasses" value="{$defaultHeaderClassesTemp}" />
<r:set_var name="componentIsMain" value="{$componentIsMainTemp}" />
<r:set_var name="componentIsRandom" value="{$componentIsRandomTemp}" />
<r:set_var name="componentHasSubnav" value="{$componentHasSubnavTemp}" />
<r:set_var name="componentFeaturettesStyle" value="{$componentFeaturettesStyleTemp}" />
<r:set_var name="componentFeaturettesID" value="{$componentFeaturettesIDTemp}" />
<r:set_var name="componentAlign" value="{$componentAlignTemp}" />
<r:set_var name="componentDisplayContext" value="{$componentDisplayContextTemp}" />
<r:set_var name="componentLimit" value="{$componentLimitTemp}" />
<r:set_var name="componentLoopBy" value="{$componentLoopByTemp}" />
<r:set_var name="componentPostscript" value="{$componentPostscriptTemp}" />
<r:set_var name="componentClasses" value="{$componentClassesTemp}" />
<r:set_var name="defaultComponentClasses" value="{$defaultComponentClassesTemp}" />

Note, the method above applies if you want your partial to function as it does for the Super Theme i.e. you are calling in a partial via “slots.” Otherwise, you can insert a partial for the incepted component manually. Just substitute this partial for lines 2 and 3 in place of the componentDisplayContext variable and the wvu-slots partials. For example, if I wanted to insert a featurettes component into a backpage component, it would look like this:

<r:partial name="includes/wvu-component-variables-temp" theme="University Relations: WVU Design System" />
<r:partial name="components/wvu-featurettes" theme="University Relations: WVU Design System" />
<r:partial name="includes/wvu-component-variables-pop" theme="University Relations: WVU Design System" />

Be sure to set values for any variables you want to apply to the featurettes component. Check out our tutorial on Building Templates Using Shared Partials for more info.