Basics
Features
Best Practices
Addon Development
Related Docs
Dark Mode

#Collections

While you can write much of your content directly onto Pages, there will be a lot of dynamic content the website uses. For example, rather than having to copy and paste a Blog Post Page and try to manually change all of the content that needs to be changed to make the new Blog Post Page, you can create a Blog Post Collection.

Like Components, Collections can be extremely simple such as a list of Services a company provides with a name, description and image for each, or as complex as a Blog Post with title, body, automatically generated slug, author, publish date, category, images, etc.

#Collection Users

Collections are designed to work well for designers, developers, and content-writers. The designer can use Collections for anything they want to use multiple times on a Page. They can very quickly make a simple list of Nav Links, a Theme for use in CSS, or Gallery Images for use on a Page.

Content writers can then use a simple form to add more Gallery Images and put them in the order they want. Any images they upload will automatically be put in the correct Media Folder and be shown on the Page with no additional code required.

The developer can add additional complex functionality such as automatically generated fields, validation rules, or special functions that can be used by the designer like blogPostList.getRecentPosts().

#Collection Basics

At their simplest, a Collection works by defining its name and fields, which can then be used when Templating. A Collection can contain multiple Entries such as a list of Blog Posts, or have a single Entry such as a single site-wide Theme.

You are encouraged to make a Collection anywhere you have a list of items, even if it's only used on a single Page, because it allows content-writers to be able to edit Pages without the help of a designer or developer.

To show how this works, we'll start by making a Theme and a simple list of Services for a Site.

First, go to the Collections screen and make a new Collection and call it "Theme". We'll use this throughout the website as a way to quickly update all of the Site's Pages when we want to make changes to colors. Select "Single Theme" in the "Entries" dropdown so there's only one Theme for the whole Site.

#Fields Basics

Now go to the Fields tab. This shows a list of all of the Fields you want the Theme to contain. Click "New Field" at the top and pick "Color" as the Field type. Name the Field "Main Color". You'll see that the Field is listed in the "Hidden Fields" section. This means it will be unavailable to content-writers, which isn't what we want. Drag and drop the field into the Form or Sidebar.

Now click the bar to the right of Main Color. You'll see it creates a spot to add another Field. Double click that area to create a new Field there. Make this Field another Color field and call it "Secondary Color". You'll see we now have two colors in our Theme. Click "Save" to save the Collection.

Now click "Theme" in the Nav Bar to see the form that was generated from the Fields. You can pick whichever colors you want.

#Using Collections in Markup

Now make a Page called "Services" at the path /services.

.services-page
  h1 Services
  .services
    .service
      h2 Phone Support
      p We provide industry-leading phone support 7 days per week.
    .service
      h2 In-Home Service
      p Call now or <a href="/schedule">Click Here</a> to schedule an appointment.
    .service
      h2 Free Delivery
      p All of our store items qualify for free delivery to your home.
.services-page
  h1
    color {{ theme.mainColor }}
  .services
    .service
      border 1px solid rgba(0, 0, 0, 0.1)
      border-radius 4px
      padding 16px
      & + .service
        margin-top 16px
      h2
        color {{ theme.mainColor }}
      a
        color {{ theme.secondaryColor }}

You can see that markup and style throughout the Site now has access to the theme object. Collection names are camelCase as are their Fields. So "Theme" becomes theme and "Main Color" becomes mainColor.

You can now go to the Theme and change colors to see those colors immediately updated anywhere they're used. Collections help make your websites as maintainable as possible.

#Collection Lists

Now you can see that this Services page has a list of services provided by the company, but we still require a designer who understands Pug to be able to edit the Page. It would be great if someone could use a form similar to the one used for the Theme to be able to add, remove, and reorder Services.

Create a new Collection and call it Service. Always name your Collections singular ("Service", not "Services"). Now let's look at the list of services on the Page. Services appear to have a name and a description.

Let's add a Text Field called "Name", and below that, a Rich Text Field called "Description". At the top of the Fields tab, chose "Name" to be the Display Field. In the General tab, set the Sort By to "(Manual)".

Now click "Services" in the Nav Bar. We can now click "New Service" at the top to create new Services for use on the site. Transcribe all of the Service names and descriptions. Note that the Description Field is "Rich Text" so it supports HTML content like links.

Note that since we selected "(Manual)", you can drag and drop Services to order them.

Now to put Services on the Services Page, update the markup to this:

.services-page
  h1 Services
  .services
    each service in serviceList
      .service
        h2 #{ service.name }
        p !{ service.descriptionHtml }

Now that this is written, content-writers can use the form to create new Services whenever they want as well as order them with no assistance from designers or developers.

In this case, note that we used descriptionHtml rather than description. This is one of the extra values added by Rich Text Fields. Just using description would output the original Markdown, where descriptionHtml is the parsed Markdown that has been converted to HTML for use on the Page.

You can also see that a "List" object is provided using camelCase. Entries in the "Service" Collection will be available in serviceList, "Blog Post" Entries will be in blogPostList, etc.

#Fields

The core feature of Collections is Fields. Each Field provides unique form inputs, validation, and extra values on the Entry.

NameDescription
TextA string. Can have a subtype of "Email", "Phone", "Full Name", or "Material Icon" which provide appropriate validation and the correct keyboard type on mobile devices.

Full Name fields require at least two names (first and last). On a Field called "Full Name", these would be available as fullNameFirst and fullNameLast.

Material Icon fields will show an icon picker to the user. See Material Icon Font for more information.
NumberThe value will be cast to a Number.
DateThe value will use a Date picker in the form. A Date will be a string in the format 'YYYY-MM-DD', a Time in the format 'HH:mm' (which is 24h time), or a JavaScript Date as a number (for example, 1650909639148). A Date called 'Published At' will also provide a Day.js object at publishedAtDate which can be used for easy formatting in markup. Day.js objects support the AdvancedFormat, Duration, and RelativeTime plugins.
ColorThe form will provide a color picker the user can use to enter a CSS color value.
Rich TextThe form will provide a WYSIWYG editor and store its data as Markdown. A Field called "Body" will provide an extra value called bodyHtml which contains the Markdown converted to HTML for use with !{ } interpolation in markup.

This Field also provides the bodyMore, bodyMoreText, bodyExcerptHtml, and bodyAfterExcerptHtml special values. These values are used in conjunction with the <!--more--> tag to provide HTML for content before and after the More Divider as well as the text label of the More Divider itself.
MediaThe form will provide an area the user can drag and drop new Media or select Media from the Media Library. You can specify the allowed Media type (Image, Video, or Audio). You can also specify an Upload Path which is the Media Folder where newly added Media will be uploaded. A Media Field called "Featured Image" will provide a value called featuredImageRef which is the Media object that was selected.
AssetThe form will provide an area the user can drag and drop new Assets or select Assets from the Asset Browser. You can specify the allowed Asset types. You can also specify an Upload Path which is the Folder where newly added Assets will be uploaded.
BooleanThe value will be true or false.
RelationThe value is a reference to another Collection Entry which can be selected from a dropdown. The value itself will be the _id of the selected Entry. A field called "Author" will provide an extra value called authorRef which is the Collection Entry that was selected.
EnumerableThe value is one of a list of options provided by a dropdown. You can determine what each option's name and value are, with values being either strings or numbers. The "name" of an option on a Field called "Difficulty" can be accessed using videoGame.difficultyEnumName or videoGameList.getEnumName('difficulty', 'easy').
ArrayArrays Fields allow you to add multiple values. You must provide an Array Item Field that determines what the Array is a list of. These are more complicated than other Fields and are explained below.
ObjectObject Fields allow you to create more Fields within a Field. These are more complicated than other Fields are are explained below.

#Array Fields

Array Fields let you add a list of Fields. For example, you could give a Blog Post a single Media Field for its header image, but then give it an Array Field called "Photos" that lets the content-writer upload multiple images that show up in a gallery.

To do this, after creating the Array Field, click "Edit Array Item" and set the type to "Media". Any added values provided by Field types are available on the Array itself. For example, a single Media Field called "Photo" would provide photo and photoRef, but an Array called "Photos" would have photo[0] and photo.ref[0]. This works with all extra Field values (.ref, .date, .html, .enumName, etc.)

The Array input in forms lets content-writers add and remove items as well as manually sort them. Each specific Field type automatically looks different within an Array.

The value of the Array Field within markup and style is a normal JavaScript Array that can be iterated over, accessed via numerical index, and has all the normal properties and functions like .length, .map(), .slice(), .filter(), etc.

#Object Fields

Object Fields allow you to create forms within a form. For example, you may want to have an address for a Business. You could create an Object Field called "Address" and then give that object its own "Line 1", "Line 2", "City", "State", and "ZIP" fields. You can then access this as business.address.line1 and so on.

It is also useful to nest Object Fields in Arrays. You could have an Array Field called Addresses, which lets the content-writer add multiple Addresses. You would access these as business.address[0].line1.

Object Fields support Display Fields, so you can decide the entire layout of the form and how it's shown in its parent Array.

#Display Fields

Display Fields are used for showing Collection Entries in the interface. You can pick which Field to use as its "name", a secondary Display Field for a subtitle, an Extra Display Field for extra data like the date or category, a Content display field which is typically Rich Text or Text representing the body, and an Image Display Field for showing the Collection Entry graphically, which should be a Media Field with an image or video, or an Asset Field pointing to an image file.

Display Fields also work using an Object Field's Fields which is useful for showing them in an Array. In the example of an Address, it is probably best to make a hidden Computed Value within the address which we can call "Display Address". Make this as a Text Field and give it the Computed Value {{ this.line1 }} {{ this.line2 }} {{ this.city }} {{ this.state }} {{ this.zip }} and set the Object Field's Display Field to "Display Address".

The content writer will see this in the Array, but of course not see it in the Address form or be able to edit it manually. More about this in Computed Values below.

#Automatic Fields

Each Entry in a Collection is automatically given _id, _createdAt, _createdAtDate, _updatedAt, and _updatedAtDate Fields. These are automatically managed by MercuryCMS. The _id Field is automatically assigned and can be used to reference specific Entries.

The Created At and Updated At Fields are automatically populated on creation and update of an Entry. These are JavaScript Date objects. The "Date" values are Day.js objects for use with formatting. For example:

.blog-post
  h1 #{ blogPost.title }
  h2 Written by #{ blogPost.authorRef.fullName } on #{ blogPost._createdAtDate.format('MMMM D, YYYY') }
  .body !{ blogPost.bodyHtml }

#Initial Values

You can set an Initial Value for Fields which is what is automatically populated when a new Collection is created. This only happens once. This isn't a default value when the user has left it blank, the user can remove the initial value if they wish.

#Computed Values

Computed values let you generate values automatically that will be used in the markup, style, or the interface. Computed values support Templating of values and support the this keyword. A simple example is a Blog Post's slug.

Create a new Collection called Blog Post, and give it a Text Field called "Title" and a Text Field called "Slug" in one row, and a Rich Text Field called "Body" in the next row.

To make the Slug automatically generated, type {{ this.title }} into the Computed Value input for the "Slug" Field. Now, if you create a new Blog Post Entry, you can see it automatically populate that field. This will of course not work for urls, so you should update the "Slug" Field to add the "kebab-case" Format.

Now you can see the Slug is automatically generated from the Title in a way that can be put into a URL. Computed values can also use interpolation, so you can hardcode content into them.

For Object Fields, you can use this to access the Object's Fields or root to Access the root Entry's Fields.

Users can click the "Override" switch on any Computed Fields to write their own. To prevent this, you can make Fields "Readonly".

#Validation

Much of a Field's validation is automatically provided by its type. For example, if you pick a Full Name type, the Collection Entry will not be able to be created if you only provide a first name.

You can also add validation rules to each field. Any field can have a "Required" validation rule, but some Field types have additional options:

TypeDescription
TextMin Length and Max Length can be specified.
NumberMin Value and Max Value can be specified.
ArrayMin Number of Items and Max Number of Items can be specified.

#Formats

Text Fields can be given Formats. Formats are applied in the order specified by the Field. You can use Formats on the Field whether it's a Computed Field or not.

The Formats are as follows:

NameDescription
camelCaseFormat the value in camelCase
kebab-caseFormat the value as kebab-case
lowercaseLowercase the value (doesn't remove non-letters)
snake_caseFormat the value as snake_case
StudlyCaseFormat the value as StudlyCase
UPPERCASEUppercase the value (doesn't remove non-letters)
Alphanumeric OnlyRemove all characters (including spaces) that are not letters or numbers
Letters OnlyRemove all characters (including spaces) that are not letters
CapitalizeCapitalize the first letter
Capitalize WordsCapitalize the first letter of every word
ReplaceReplace a value using JavaScript Regular Expressions and a replacement value
ReverseReverse the text. Most useful as a Computed Value so it doesn't reverse each time it's updated
TrimTrim whitespace from the beginning and end of the value

#Collection Functions

You may want to add reusable functions to your Collection Entries or Collection Lists. For this, you can use Collection Functions. We'll look at two examples here.

For the first example, we'll make a function to get a specific amount of recent Blog Posts from the Blog Post Collection. First, make sure there's a Date Field called Published At on your Blog Post Collection and set Published At dates for all of the Blog Posts.

Go to Functions in the Blog Post Collection settings and pick "Blog Post Collection" from the Location dropdown and write this function:

function getRecentPosts(count=10) {
  return this.slice().sort((a, b) => {
    a = new Date(a.publishedAt).valueOf()
    b = new Date(b.publishedAt).valueOf()
    if (a < b) return 1
    if (b < a) return -1
    return 0
  }).slice(0, count)
}

This function uses the this keyword, which refers to the blogPostList since this is a function on blogPostList. It then copies the Array so it doesn't affect the original Array and sorts it by the "Published At" Field.

Now, in a Page's markup, we can do this:

.home-page
  h1 Recent Posts
  .blog-posts
    each blogPost in blogPostList.getRecentPosts(5)
      .blog-post
        a(href=`/blog/${blogPost.slug}`)
          h2 #{ blogPost.title }
        .date #{ blogPost.publishedAtDate.format('MMM D') }

Functions can also be placed on the individual Collection Entries rather than the list. Let's write an example for a Nav Link. First, let's make a Collection called "Nav Link" which has two Text Fields: "Name" and "Path".

Now we can add a Function to it an pick "Each Nav Link" from the Location dropdown. Write this function:

function isNavigated() {
  if (page.path != '/' && this.path == '/') return false
  return page.path.startsWith(this.path)
}

You can see this can tell us if the Page we're viewing is the currently navigated page. For example, we would want the "Blog" Nav Link that links to /blog to be highlighted if we were at the Page /blog/my-first-post. Here's how it would look in markup:

.nav-links
  each navLink in navLinkList
    a.nav-link(href=navLink.path class=navLink.isNavigated() && 'selected') #{ navLink.name }

In the style we could do:

.nav-links
  a.nav-link
    color inherit
    text-decoration none
    padding 16px
    transition color 0.2s
    font-weight 500
    &.selected
      color {{ theme.mainColor }}
    &:hover
      color {{ theme.mainColor }}

#Build Script

Collection Build Scripts work the same way as Component Build Scripts. See Component Build Scripts for information.

#Importing and Exporting Collections

When building websites, you will create many Collections with different Fields, Functions, and Data. You will inevitably want to use some of the same functionality to build another Site.

To do this, you can go to the Settings screen for the Collection you want to export and click "Export". You can then import it into another Site from its Collections screen. This does not import or export the Collection's Entries, only the Collection's definition.

There are also a number of built-in Collections available in the Collection Library, which can be found on the Collection screen.