Pattern Library

A pattern library is a collection of designs used across the website. It is a culmination of the brand identity, design principles, and web best practices put into design artifacts.

Objects

Content Section

Content sections are used to separate different topics and can be coloured to further differentiate between them. It also functions to contain the content within the breakpoints of the webpages.

Welcome to Liz!

The content section is a generic container to encapusulate a part of the webpage. This part is totally customizable.

  • Background Image

    Sometimes an image instead of a colour should be the background of a content section.

    You can customize the content here! Add an overlay to make the content more readable.

  • Content Spacing

    Setting the space adjusts the padding around the content. Note that setting space to 'overlap-top' will move the current content section up to slightly overlap the previous content section.

    Top 'space' => 'top'

    Content Section Title

    Content section subtitle

    This content section has more padding at the top.

    Bottom 'space' => 'bottom'

    Content Section Title

    Content section subtitle

    This content section has more padding at the bottom.

    Small 'space' => 'small'

    Content Section Title

    Content section subtitle

    This content section has minimal padding at the top and bottom.

    Overlap Top 'space' => 'overlap-top'

    This content section applies a margin to the top, overlapping its elements with the elements above it.

Content Section Header

Contains the styles for titles and subtitles.

Content Section Title

Content section subtitle

  • Subtitle Width

    Setting the space adjusts the padding around the content. Note that setting space to 'overlap-top' will move the current content section up to slightly overlap the previous content section.

    Default

    Content Section Title

    This is a very long subtitle and it is not set to be any wider. See how this subtitle has a bigger margin.

    Wide 'subtitleWidth' => 'wide'

    Content Section Title

    This is a very long subtitle and it is set wider to fit more characters on one line. See how this subtitle is slightly wider.

Layouts

Our grid component uses grids for rows and grid-cells for columns. The grids are based on a two-dimensional grid system called flexbox. If you are unfamiliar with flexbox, take a look at CSS Tricks' flexbox guide.

Liz’s grid component is fully responsive and can create layouts for all device sizes. To learn about all the breakpoints liz supports, refer to the section on breakpoints.

When deciding which column size(s) (grid tiles and grid-cell widths) to use, always make sure the copy is appropriately spaced - approximately 10 words per line. It is okay to break this rule when needed, but keep in mind it exists to prevent reader fatigue.

Grids

Grids act as rows for the columns (grid-cells). Each grid can display up to 12 columns in a continuous row, however there is no limit to how many columns can be in a grid, as any combination of columns will automatically wrap into the next row. Below is an example of how these 12 columns lay over the safe.com homepage:

Homepage with 12 overlaying columns

The grid component should always be contained within a content-section, which restricts it to a max width (refer to the content-section object for more information). In practice, the above 12 columns will be combined to create 6/3/2 column structures depending on device sizes, as illustrated below.

Desktop, tablet, and mobile with overlaying columns

These column structures are recommendations for the maximum number of columns on a single page. A common 2-column layout could look like the following:

FME (aka. Feature Manipulation Engine) is a data integration platform with the best support for spatial data worldwide. Easily address the question of “where” and convert data precisely for your needs. Build your own custom workflows that improve access to data and solve compatibility issues, without needing to code anything.

FME Form

Grid Cells

Grid Cells are the columns that make up each row (grid). They can be as small as 1/12 of a row, but in practice shouldn't be less than 1/6. Refer to the Grid Sizing Language section for all the available sizes. Below is an example of possible combinations of grid sizes we can achieve with liz.

1/1

1/5

4/5

1/4

3/4

1/3

2/3

1/2

1/2

4/6

2/6

6/8

2/8

8/10

2/10

10/12

2/12

  • Grid Spacing

    Grid margins

    Spacing between cells can be customized, and is called on the grid component. This can be set for both tiled and non-tiled grids.

    Spaced 'spacing' => 'spaced' (1 rem)
    Spacey 'spacing' => 'spacey' (1.75 rem)
    Spaciest 'spacing' => 'spaciest' (2.5 rem)
    Flush 'spacing' => 'flush' (0 rem)
  • Grid Cell Ordering

    Columns (grid-cells) can be reordered depending on the breakpoint. Use the following code to reorder your columns at each breakpoint to yield the best content flow on Desktop, Tablet and Mobile.

    First defined grid cell.

    Second defined grid cell

  • Grid Sizing Language

    Grid sizes are named using phrased fractions for semantic readability. The fractions go from whole to twelfths and have different semantics depending on whether they are used in grid tiles or grid-cell widths.

    Tiles
    one, halves, thirds, quarters, fifths, sixths, sevenths, eighths, ninths, tenths, twelfths
    Widths
    one-whole, one-half, one-third, two-thirds, one-quarter, two-quarters, three-quarters, one-fifth, two-fifths, three-fifths, four-fifths, one-sixth, two-sixths, three-sixths, four-sixths, five-sixths, one-eighth, two-eighths, three-eighths, four-eighths, five-eighths, six-eighths, seven-eighths, one-tenth, two-tenths, three-tenths, four-tenths, five-tenths, six-tenths, seven-tenths, eight-tenths, nine-tenths, one-twelfth, two-twelfths, three-twelfths, four-twelfths, five-twelfths, six-twelfths, seven-twelfths, eight-twelfths, nine-twelfths, ten-twelfths, eleven-twelfths

Breakpoints

The breakpoints we use are based on the screen widths where our content starts to break. Use these breakpoints when setting tiles, widths, and orders. This allows us to create responsive styles for each device.

Breakpoint Description
mobile min-width: 0px
tablet min-width: 480px
sm-laptop min-width: 720px
laptop min-width: 960px
desktop min-width: 1200px
widescreen min-width: 1600px

Inline Group

This is a flex container to put elements into an inline group. Modifiers can change the flex behaviour of child elements, and make the group stack at different breakpoints.

.inline-group

An inline group child element

Media Object

These are abstract layout classes to display an image next to text. Encapsulate each column in a media-object__section.

See Foundation's Media-Object documentation for more reference on functionality.

components.media-object.media-object
</>
isStack => bool : if true, will stack vertically on mobile
padded  => [small, medium, large]
components.media-object.media-object-section
</>
padded => [small, medium, large]
main   => bool : sets the main section

Why Hello There

This is quite an exciting encounter, now isn't it?

Components

Accordions

Accordions are best used with optional content or information that may not be applicable to all users. For example, FAQs or further details of features that apply only to those interested in knowing more. Be wary that hidden content is easily missed, so do not put any vital information within them.

To keep the accordion accessible, there is the titleTag variable to allow each of the item to have the appropriate heading level. If the size of the heading needs to be changed, there is the titleSize variable.

See Foundation's Accordion documentation for more reference on options and javascript functionality.

components.accordion.accordion
</>
type         => if not default, set to [dark, narrow, image-feature-right]
titleTag     => html tag of title, default is 'p'
titleSize    => size of the title tag, default is 'h5'
hasNav       => bool : enable expand/collapse all navigation
contentArray => only pass this in if 'content' contains only text or minimal html (inline tags only) :
                  [
                    [
                      'title' => 'accordion title text',
                      'content || description' => 'accordion content',
                      'deepLink' => 'optional deeplink href'
                      'featureImgUrl || image' => 'optional url of a feature image for that style'
                    ], ...
                  ]

slideSpeed           => '500'
multiExpand          => true
allowAllClosed       => true
// if no custom deepLinks are set in the contentArray, you can pass an id
// to the accordion, and deep-links will be generated
deepLink             => false
updateHistory        => false
components.accordion.accordion-item
</>
* title          => item title
  titleTag       => html title tag, default is 'p'
  titleSize      => size of the title tag, default is 'h5'
  isActive       => bool : whether item is the default active item, should be set for at least one item per accordion
  deepLink       => str  : the deep link href if enabled
  isCustomLink   => bool : does this item use a custom open/close link?
components/accordion.js

Default accordion

Typically used in FAQ sections.

Dark accordion

This was made to fit with video content (such as on the webinars and training pages), but can fit anywhere with a dark theme.

'type' => 'dark'

Compact accordion

For more details relating to a larger topic, but are optional.

'type' => 'narrow'

With navigation

Additional controls can expand and collapse all items. In order for them to work, the appropriate javascript dependencies must be included.

Note: This is not compatible with the feature-image accordion, as that one can only display one image at a time.

'hasNav' => true

Feature-image accordion

Intended to be used with media content on the right side.

'type' => 'image-feature-right'

Banners

Banners are attention-grabbing headers or sections. They start-off most pages with a headline, and may be sprinkled (sparingly) as call-to-actions for prominent resources.

The background image, colour, and overlay strength can be customized. Keep in mind banners work best with darker background images, which make light text and buttons pop out.

  • Sizing

    Sizing increases the padding applied to the top and bottom of the banner; use larger banners for more prominent titles and for attention-grabbing. If the banner is merely for starting the page, use a smaller size to keep vital content above the fold.

    Large 'size' => 'large'
    Medium 'size' => 'medium'
    Small 'size' => 'small'
    Thin 'size' => 'thin'

    Depending on the span, a smaller button can be used to balance the text.

Banner Title Block

The title block contains the default headline styles, with a title, optional subtitle, and optional call-to-actions.

  • Title Width

    Wide 'titleWidth' => 'wide'
  • Subtitle Width

    Wide 'subtitleWidth' => 'wide'

Buttons

Buttons are used for actions, like submitting a form or downloading a document. They express where a user will go or what action will occur when the user interacts with it. Buttons can contain text, icons, and even instantiate a modal.

  • Button Types

    Primary 'type' => 'primary'

    The primary button is orange to indicate the primary action on the page.

    Secondary 'type' => 'secondary'

    The secondary button has a weaker visual weight and can be placed alone or in conjuction with a primary button.

    Hollow White 'type' => 'hollow-white'

    Hollow white buttons are versions of the secondary button to be used on dark backgrounds.

    Arrow Link

    Arrrow link buttons contain a right-facing arrow and are used to add visual weight to an ordinary anchor tag.

    Buttons with Icons

    Use buttons with tokens for small interactions that don't lead the user off the current page.

    Play Media 'type' => 'play-media'

    The 'play-media' button is used explicitly for opening modals that will play media, or similar purposes. It requires a 'uuid', 'id', and 'thumbBgUrl' for the image behind the icon.

    Modal

    Including 'uuid' and 'id' will automatically trigger a modal to appear, no matter the type set to the button. This is useful when creating a custom look for the button.

    Contextual Action
    Note: Test the download links! There are some gotchas depending on file types and server permissions.

    If more info is necessary to describe the resulting action. For example, downloading large resources.

Callout

Used to draw attention to messages. If the $type is set, an icon will be inserted next to the message.

components.callout.callout
</>
type          => [(alert, warning, error), info, success, hollow]
semanticIcon  => if 'type' is not set, must set an icon name to go with message

style         => * very specific use case for forms, as js will inject inline styling

something must be done!

error

Something must be done!

question-circle

Some info you might need to know.

check-circle

Successful!
Good job on making it this far!

Hollow style!
For less intrusive displays!

Cards

Cards are boxes that have drop shadows, which draw attention and "lift" them off the page. Since Blade code can be passed directly into cards, any kind of content may be nested inside them.

As a layout pattern, cards can differentiate parts of the main content, breaking it into chunks of separate yet related information.

See Foundation's documentation for more details and examples.

This is a card!

Card section

Divides card content into distinct segments. By default, these sections also have padding of their own.

Hello There

Welcome to liz!

Card lineup

Can be used to add a row of cards linking to related resources. It is recommended you include between 2 and 5 cards.

  • Card variations

    Since just about anything can go inside a card, they're an especially versatile pattern. Here are a couple more examples of how they can appear:

    Why Hello There

    This is an interesting encounter, now isn't it?

    $199 CAD

    Button
    Why Hello There

    This is an interesting encounter, now isn't it?

    $199 CAD

    Button
  • Fluid card height

    To force a card to vertically fill its parent element (e.g. a grid cell), you can apply the card--fluid-height class:

    This card's height is not fluid

    This card's height is.

Chips

An inline element that contains a small chunk of information.

components.chip.chip
</>
color      => [blue, green, red, indigo], default is gray
isBordered => bool : whether bordered or not
default chip

Colours

See the colour palette for more options.

'color' => 'color'

default chip
blue chip
green chip
red chip
indigo chip

Bordered

For increased differentiation between the chip and the background.

'isBordered' => true

default chip
blue chip
green chip
red chip
indigo chip

With icons

Icons can be used to enforce the message of the chip or add visual recognition.

comment blue chip
edit green chip
slides red chip
calendar indigo chip

Cloak

When used in an element that has a Vue instance mounted to it, the cloak component and its contents remain visible until that instance is ready. It does so by implementing the v-cloak directive.

By default, the cloak component displays the "three-bounce" spinner included in SpinKit. You may inject any alternative content you wish by using the slot:

Now loading...

Hash Heading

Use the hash heading to allow for inline linking to sections without having the main navigation cover the heading. In general this heading should be used by default for all headings as it does not cause any extra overhead compared to a regular heading.

Heading 1

Heading 2

Heading 3

Blog Usage

If this is being used on the blog, then use the following html when creating headings. Make sure to change the id="" and Heading Name appropriately.

Heading Name

Orbit

Sliding content. Use these sparingly and be sure preceding slides (any slide after the first) do not contain vital information as they will likely be missed or skipped.

See Foundation's Orbit documentation for more reference on options and javascript functionality.

components.orbit.orbit
</>
* numSlides       => num  : how many slides, used for making bullets
  isFitDropshadow => bool : enable to allow dropshadow containers inside slides
  extrudeControls => str  : [mid, full, ext]
components.orbit.orbit-slide

Default

The default styles has no layout restrictions, and few default styles; it includes the next/previous arrows, bullets, empty slide sections, and an optional image caption.

  • Space
    Space, the final frontier.
  • Space
    Space, the final frontier.
  • Space
    Space, the final frontier.

Extruded controls

Controls can be extruded in depth levels depending on the slide content. If content contains left-justified text, you may want to extruded the controls to avoid readability issues.

'extrudeControls' => 'mid'

  • Space
    Space, the final frontier.
  • Space
    Space, the final frontier.
  • Space
    Space, the final frontier.

'extrudeControls' => 'full'

  • Space
    Space, the final frontier.
  • Space
    Space, the final frontier.
  • Space
    Space, the final frontier.

'extrudeControls' => 'ext'

  • Space
    Space, the final frontier.
  • Space
    Space, the final frontier.
  • Space
    Space, the final frontier.

Fitting slides inside another element

Orbit can easily be fit inside other containers or elements. In the below example, orbit is wrapped inside a card element. If the slides contain text, extrude the controls to improve readability.

'extrudeControls' => 'ext'

  • Slide One

    With some content

  • Slide Two

    With some content

  • Slide Three

    With some content

Fitting containers inside the slide

Fitting elements that have dropshadows will require a few conditionals to be set for the elements to display properly. In this example, a card is called inside each slide.

'isFitDropshadow' => true
'extrudeControls' => 'mid'

  • Slide One

    Bacon ipsum dolor amet filet mignon beef ribs corned beef, drumstick chicken spare ribs swine ut shankle. Ham hock nostrud pork belly pork chop ea laboris voluptate jerky tri-tip t-bone dolore aliqua picanha ad chicken.

  • Slide Two

    Short loin nisi alcatra et ullamco jerky, sirloin laboris turducken dolore. Ham hock ipsum ut bresaola consequat beef ribs, buffalo brisket meatloaf rump boudin consectetur pork belly in.

  • Slide Three

    Kielbasa eiusmod reprehenderit nisi, ground round porchetta enim. Laboris est duis dolore tri-tip, shoulder irure sunt. Fatback anim ball tip, tongue bresaola jowl aute veniam non eu ut.

Quote Orbit

A full section pattern used to display a set of quotes and other testimonials. To use this pattern, the JavaScript object will need to be created.

patterns.quote-orbit
</>
Section pattern for an orbit with quotes.
Requires loading quote-orbit.js in the page.

$content = [
    [
      'quote' => str: text of the quote,
      'name' => str: name of the speaker,
      'company'=> str: name of the company,
      'buttonText' => str: Optional Button - text of cta button,
      'url' => str: Optional Button - link of the cta button,
      'slideButtonImg'=> str: image link of the button of each company,
      'slideBGImg'=> str: image link of the background
    ]
  ]
components/quote-orbit.js
</>
import SafecomQuoteOrbit from '../components/quote-orbit.js';
var orbit = new SafecomQuoteOrbit($('.js-quote-orbit'));

  • "Our rack space costs (real estate on our data center floor) were $3,800 per month. Add to that the hardware costs, etc and you start to see why moving to the cloud was a no brainer for us."
    Anthony Davis
    State of Arkansas
  • "Other state agencies are now seeing the benefit of using the cloud to deliver large data volumes quickly and reliably."
    Brett Madsen
    MapData Services
    Read The Story
  • "You could remove every single piece of software from my desktop, but the one that I need is FME"
    Roland Martin
    Arup

*Pagination

some description

Patterned Banner

A special banner component composed of a hero pattern from heropatterns.com and an optional background color or gradient. The component requires a pattern argument, and the pattern SVGs are stored as URL strings in config/style.php.

  • Patterns

    There are currently 5 patterns to choose from:

    Pattern names can be passed in snake-case or kebab-case:

  • Additional Options

    The component accepts optional fill, background, and opacity arguments. These can be used to further customize the pattern and background colors.

    The background parameter can accept a linear gradient or a solid color:

*Progress Bar

*Reveals (Modals)

The reveal is used for call-to-action forms and/or content.

Side-Tabs

Side-tabs are similar to Tabs, and used to change between different content views. Each item of the side tab must be wrapped inside a side-tabs-item block.

Generally, the light style is used for text-based content, and the dark style is for multimedia (videos and slides).

components.side-tabs.side-tabs
</>
header      => for extra context, a header can be set
headerTag   => html tag if 'header' is set, defaults to 'h5'

isDark      => bool : set the dark theme
isScroll    => bool : sets tabs to be scrollable within container
isBordered  => bool : set borders between items
isStretch   => 
components.side-tabs.side-tabs-item

Bordered

For slight separation between items.

'isBordered' => true

Scrollable

When the side-tabs is related to content that has a limited height.

'isScroll' => true

Header

For extra context, a header can be added.

'header' => 'Side-tabs header'

Dark

Generally for multimedia content, accompanying a video as a table of contents.

'isDark' => true

Site Alerts

Use a site alert to display a site-wide message, visible on all pages of Safe.com. Choose an appropriate semantic colour depending on the message you want to convey and set a date on which you want the message to disappear.

Important #1: If you're working on the site alert and it's not visible to you, it's likely you dismissed it. Search for hide_site_alert in your cookies and delete it. This will restore the alert to its default state.

Important #2: The site alert should be included in the header of the website so it can display properly. Add it to /resources/views/templates/header.blade.php, as the first child of <header class="js-header header header--fixed">.

  • Colors

    Each alert colour holds a specific semantic meaning. Be sure to pick the right one for the message you're trying to convey. See below for examples:

    Info 'alertColor' => 'info'

    When you want to announce an informative message (eg. a new FME release).

    FME 2021.0 is available.

    Warning 'alertColor' => 'warning'

    When announcing maintenance or possible downtime (eg. server maintenance, possible server outages, etc.)

    Servers maintenance scheduled for Saturday.

    Danger 'alertColor' => 'danger'

    When there is a critical risk to customers (ie. security vulnerabilities).

    FME 2015.1 has a security vulnerability.

    Success 'alertColor' => 'success'

    When announcing successful projects or public campaigns (eg. a successful charity).

    We raised $10,000 for charity.

  • Timing

    You can control when and how long a site alert appears by adjusting the dates passed to the component.

    'showUntil' => '2030-01-01T00:00:00Z-0800'

    Example of a date in the future, in which case the alert should appear.

    Ohh, hi. I should be here.

    'showUntil' => '2020-03-17T00:00:00-0800'

    Example of a date in the past, in which case the alert should not appear.

*Slider

Tables

For tabular data, but it is not a very responsive layout style. There are workarounds to allow tables to scroll, or for certain columns to hide/show at certain breakpoints.

Default

Header Header Header Header
data data data data
data data data data
data data data data

Table with extra section headers

When the overall table topic contains distinct sub-sections, they can be separated with this style. The table section is highlighted, and the successive rows remain white.

Ex (Jun 2018): The Tech-Specs page

.table__section

Header Header Header Header
Table Section Header

Inside the table section.

data data data data
data data data data
Table Section Header

Inside the table section.

data data data data

Table standalone row

This is meant for 1-3 rows of content, with the data taking more precedance; therefore, the data should be quite self-explanatory even without the headers.

.table--standalone-row

City Country Date Host
Surrey Canada June 6, 2018 Safe Software

Table scrolling

Tables can be wrapped with the class to prevent layout breaking on smaller screens.

.table--scroll or .table--scroll@breakpoint

Table hide-show

Table rows and cells can be hidden-shown to minimize content on smaller screens.

.table--hide@breakpoint and .table--show@breakpoint

Tabs

Tabs toggle between content. Generally, the light style is used for text-based content, and the dark style is for multimedia (videos and slides).

See Foundation's Tabs documentation for more reference on options and javascript functionality.

components.tabs.tabs
</>
* tabsItems   => 
    [
      [
        'title'=>'title', 
        'itemId'=>'id'],
      ], [...]
    ]
  activeTabIs => tab number that's active, starting at 1; default is 1
  color       => [dark, black, hollow]
  options     => data options from Foundation, without the 'data-' suffix
components.tabs.tabs-content
</>
* id          => id corresponding to tab id
  color       => [dark, black]
  activeTabIs => index of active tab, start from 1
  tabsItems  => arr : pass in the same array as for the tabs
    [
      [
        'title'=>'title', 
        'itemId'=>'id'],
      ], [...]
    ]

* @section('itemId'): define sections for each item within the component
components/tabs.js

Default tabs

This is the content inside Tabby.

And this is content inside Tabtab!

Dark tabs

'color' => 'dark'

This is the content inside Tabby.

And this is content inside Tabtab!

Hollow tabs

'color' => 'hollow'

This is the content inside Tabby.

And this is content inside Tabtab!

And this is content inside Tabtabtab!

*Tooltip

Tooltips are for providing context specific information as an aside, or as help for those wanting more info. Vital information should never be hidden in a tooltip.

Tooltip is indicated by a question mark in a circle. Clicking on the tooltip button opens it and does not hide until you click somewhere else.

Vidyard Player

Embeds a Vidyard video by its UUID.

The version attribute can specify a particular version of the Vidyard API to use. Otherwise, the component will use the global default in config/app.php, which is currently 4.

  • The legacy Attribute

    Prior to version 4 of the Vidyard API, it was common for players to be embedded using inline script tags, instead of placeholder images.

    If the legacy attribute is set to true, this older method of embedding will be used. It exists to preserve the function of older players on the recorded training and webinar pages, and shouldn't be used for new embeds.

Code-Reference

Blade

Most of our components are implemented in Blade, the Laravel front-end template engine. This is some general reference on code that affects all our Blade templates.

Common Component Attributes

Most components come with common variables to set extra classes, id's, data-attributes, etc. These apply ontop of the component-specific variables that can be set.

class => str : any extra classes to append to the component
attr  => ["attribute" => "value", ...] : an array of extra attributes


deprecated, but still exists:

extraClasses => replaced by class
id           => replaced by attr
dataAttr     => replaced by attr

The attribute variable can be used to set any html attribute. For example:

@include('components.card.card', [
    'class' => 'extra-fancy-class',
    'attr' => [
      'id' => 'lz-card card-id',
      'aria-label' => 'some aria label',
      'role' => 'navigation',
      'data-attribute' => 'some value',
    ]
])

Adding the Common Attributes to a New Component

To include these helper variables in a new component, include the common-variables PHP file into the component Blade template, and output the $class and $attr variables where applicable. For example, in the card Blade template:

@php
  include($_SERVER['DOCUMENT_ROOT'] . '/../resources/views/components/_helpers/common-variables.php');
@endphp

<article class="card {{ $classes }}" {!! $attrList !!}>
  @slot
</article>