How to Make a Hero Image Modal Block using Atomic CSS

This article covers how to use Element to build a custom Block for the VOLT Store that shows text with a call-to-action over an image. This tutorial explains Atomic CSS, Element’s AMP-ready CSS library.

How VOLT has best-in-class page speed

Out of the box, VOLT is configured to keep your ecommerce store loading fast, because increased speed means increased revenue.

On slow mobile devices, page loading becomes even more important.

That’s why Google started AMP (Accelerated Mobile Pages), a way of helping websites like your VOLT Store load quickly on mobile devices.

AMP pages show up in Google search results on mobile, and speed is a ranking factor for Google search ranking.

To achieve that lightning-fast speed, the VOLT Store uses Atomic CSS, a built-in cascading stylesheets (CSS) library with fast load times and readable CSS class names.

Using Atomic CSS helps you keep your VOLT Store’s total CSS under the 50KB limit for CSS on AMP pages.

This article will explain the use of Atomic CSS with the example of making a hero image modal as a custom Block for use in the VOLT Store using Element.

What is Atomic CSS?

Atomic is a mobile-first, layout-focused, CSS library based on Tachyons for use on VOLT storefronts. The intention is to provide only the most frequently used CSS for constructing your content.” —Styling Your Block With CSS in the Element Platform Documentation 

When building custom Blocks using Element, Atomic CSS is how you select CSS styles for layout properties like height, width, position, and spacing.

Atomic CSS offers great control over many CSS properties. The complete reference is found in the element-atomic-css GitHub repository, which lists all Atomic CSS classes.

While custom CSS is very possible (and easy) using Aphrodite, the “CSS-in-JS” (or “JSS”) library that Element also has built-in, this article will focus on the use of Atomic CSS.

Of course, Aphrodite will be used as needed, and this article will help illustrate what needs to be configured in Aphrodite (as custom styles) vs. what can be selected from Atomic CSS.

Other articles have discussed using Aphrodite to create custom CSS classes in custom Blocks using Element. For more information, please read the previous articles on customizing font sizes or font faces using Element, or the article on unit testing CSS in Element.

For more information on using CSS in Element, please refer to the sections Atomic CSS Framework and Style A Block with Aphrodite from the Element Platform Documentation.

What is a hero image modal?

A hero image is a featured image, front and center, and a modal is a dialog box with text. Put together, a hero image modal is an effective web design for your VOLT Store.

The style of this banner is inspired by modal boxes, which are website dialog boxes shown with the background grayed out.

Graying out the background helps capture attention, because the modal usually needs to be closed by the website user.

In this tutorial, you will learn to make a Hero Image Modal Block, where a modal-style box with call-to-action is shown over an image.

This custom Block will use the same styling as a modal box to highlight a call-to-action in the form of a button link, but without disabling the rest of the page.

The background image will be customizable by the owner of the VOLT Store, who will be able to upload and manage images using VOLT’s Site Designer.

Making a custom Hero Image Modal Block

This tutorial will assume you understand how to create and publish an Element Block. If you have not made a custom Element Block before or need a refresher, please refer to the article “Building An Element Page Tutorial” (15 min read) in the Element Platform Documentation or watch the YouTube playlist (27 min) “Element Tutorial | VOLT Learning Center.

You must be authorized to develop custom Blocks to continue with this tutorial. Please refer to “How To Get Approved To Develop Blocks” over in the Element Platform Documentation.

This tutorial will primarily focus on the spacing.css file from Atomic CSS, which covers padding and margin with classes like:

.pa0 {
padding: 0;
}
.pv0 {
padding-top: 0;
padding-bottom: 0;}
.ph0 {
padding-left: 0;
padding-right: 0;
}
.ma0 {
margin: 0;
}

Atomic CSS also comes with breakpoint selectors for creating different mobile and desktop website designs. The breakpoints are:

// Small (the default), <30em width
.pa0 {padding: 0;}

// Not small, >30em width
.pa0-ns {padding: 0;}

// Medium, >30em & <60em width
.pa0-m {padding: 0;}

// Large, >60em width
.pa0-l {padding: 0;}

For more information on handling breakpoints in Tachyons (the framework Atomic CSS is built-on), please refer to the article Tachyons CSS by Justin Tomich on his blog.

In the next section, you will learn to combine these CSS classes to achieve the effect of a modal box over a hero image banner.

Create a new Block with the Element CLI

You should already be logged in to the Element Command Line Interface (CLI). If you are not, then enter the terminal command:

element login

The login command will prompt you for the username and password you use with VOLT’s Site Designer.

In the directory where you keep your Element Blocks, make a new Block called “HeroImageModalBlock” with the following terminal commands:

element new HeroImageModalBlock
cd HeroImageModalBlock
npm install

Now, initialize a git repository in the directory to track changed files with the terminal commands:

git init
git add -A
git commit -am "Initial Commit"

Now is also a good time to publish your repository online, such as to GitHub. (For help, see Adding a repository from your local computer to GitHub for instructions using GitHub Desktop.)

Update /src/configs.js

The first task is to set up what will be configurable by the user in the /src/configs.js file.

In this case, the user will have control over the background image, various colors, three lines of text, and the button link URL.

Open /src/configs.js in your preferred text editor or IDE, and replace the contents of the file with this code:

import { ElementPropTypes } from "@volusion/element-proptypes"

export const configSchema = {
section1: {
type: ElementPropTypes.sectionHeader,
},
image: {
label: "Background Image",
type: ElementPropTypes.image,
},
section2: {
type: ElementPropTypes.sectionHeader,
},
modalBackgroundColor: {
label: "Background Color (Modal Box)",
type: ElementPropTypes.color,
},
modalTextColor: {
label: "Text Color (Modal Box)",
type: ElementPropTypes.color,
},
buttonBackgroundColor: {
label: "Background Color (Button)",
type: ElementPropTypes.color,
},
buttonTextColor: {
label: "Text Color (Button)",
type: ElementPropTypes.color,
},
section3: {
type: ElementPropTypes.sectionHeader,
},
lineOneText: {
label: "Line One",
type: ElementPropTypes.string,
},
lineTwoText: {
label: "Line Two",
type: ElementPropTypes.string,
},
buttonText: {
label: "Button Text",
type: ElementPropTypes.string,
},
buttonLink: {
label: "Button Link (URL)",
type: ElementPropTypes.string,
},
}

export const defaultConfig = {
section1: "Background Image",
image: {
uriBase: "http://d21ivvgspl06jm.cloudfront.net/",
imagePath: "element-block-assets/slideshow/slide2.jpg",
altText: "Monument Valley",
width: 1600,
height: 500,
},
section2: "Colors",
modalBackgroundColor: "rgba(0, 0, 0, 0.8)",
modalTextColor: "white",
buttonBackgroundColor: "rgb(20, 161, 20)",
buttonTextColor: "white",
section3: "Text",
lineOneText: "50% OFF SALE ITEMS",
lineTwoText: "NOW OFFERING THE BEST DISCOUNTS OF THE YEAR",
buttonText: "Shop Our Best Deals",
buttonLink: "/products",
}

This code establishes the configurable props for use in your Hero Image Modal Block. These props are what will be editable by the user of the custom Block in VOLT’s Site Designer.

The props are of the “image,” “color,” and “string” Element Proptypes. The user will have access to VOLT Site Designer’s image uploader through the “image” Proptype. The image is specified with a default placeholder image in the defaultConfig export statement.

For the “color” Proptype the user will have access to a color picker in Site Designer. The background-color CSS properties will set by default to an 80% opacity black for the modal and a solid green for the button, specified in rgba and rgb formats.

The “text” Proptype simply specifies the three lines of text for the headings in the modal.

For more information, refer to the list of all Element Proptypes in the Element Platform Documentation, or see the previous article Element Proptypes Explained for Custom Blocks in the VOLT Store.

Update /src/Block.js

Next you will be writing the custom Block itself, which will combine Atomic CSS and Aphrodite styles and insert the text (string) props configured in the last file.

Open up /src/Block.js in your text editor or IDE.

Replace that entire file with this code:

import React from "react"
import { css, StyleSheet } from "aphrodite/no-important"
import { getStyles } from "./getStyles"
import { defaultConfig } from "./configs"

const Block = (props) => {
const classes = StyleSheet.create(getStyles(props))
const { joinClasses } = props // Helper function to combine Atomic CSS with Aphrodite
const { image, lineOneText, lineTwoText, buttonText, buttonLink } = props
return (
<div className={joinClasses("w-100 center", css(classes.wrapper))}>
<div className="relative">
<div className="absolute absolute--fill w-100 h-100">
{image.uriBase && (
<img
className={joinClasses("dib w-100 h-100", css(classes.image))}
src={image.uriBase + image.imagePath}
alt={image.altText}
width={image.width}
height={image.height}
/>
)}
</div>
<div
className={joinClasses(
"v-mid ph3 pv4 pv5-m pv6-l relative tc",
css(classes.modalWrapper)
)}
>
<div
className={joinClasses(
"w-80-m w-60-l center ph3 pv4 pa5-ns dib",
css(classes.modal)
)}
>
<div>
<h2 className={joinClasses("ma0", css(classes.lineOne))}>
{lineOneText}
</h2>
<h3 className={css(classes.lineTwo)}>{lineTwoText}</h3>
</div>

<a href={buttonLink} className={css(classes.buttonLink)}>
<h4
className={joinClasses("pv3 ph4 dib ma0", css(classes.button))}
>
{buttonText}
</h4>
</a>
</div>
</div>
</div>
</div>
)
}

Block.defaultProps = defaultConfig
export default Block

This custom Hero Image Modal Block displays the text content in three headings: <h2>, <h3>, and <h4> for the button.

The code uses Element’s joinClasses() function (props.joinClasses) to combine Aphrodite custom styles with Element’s built-in Atomic CSS classes.

The Hero Image Modal Block uses the “ma0,” “ph3,” and “pv4” CSS classes from the previously-mentioned Atomic CSS spacing.css file.

This improves the spacing of the Block by setting the margin and padding CSS attributes to 0 margin (“ma0”), 1rem horizontal padding (“ph3”), and 2rem vertical padding (“pv4”).

Atomic CSS is based on powers-of-2, with the value of the distance setting doubling each level from “pa1” (padding 0.25em) to “pa7” (padding 16rem), measured in the rem CSS unit.

The text headings are centered in a modal box, which has a width of 80% of the screen on medium displays (“w-80-m” in Atomic CSS) and 60% of the screen on large displays (“w-60-l”). On mobile displays, the modal simply has some padding from the sides of the screen.

For the complete list of all CSS classes contained in Atomic CSS, please see the atomic.css file in the element-atomic-css GitHub repository.

The next section of the article will explain every Atomic CSS and custom class used in detail.

Looking at the Atomic CSS Styles

In this section, the # character is used to indicate that elements are contained within the previously-mentioned elements, to help you understand the modal effect.

<div className={joinClasses("w-100 center", css(classes.wrapper))}>
#<div className="relative">
##<div className="absolute absolute--fill w-100 h-100">
###<img className={joinClasses("dib w-100 h-100", css(classes.image))}
##<div className={joinClasses("v-mid ph3 pv4 pv5-m pv6-l relative tc", css(classes.modalWrapper))}>
###<div className={joinClasses("w-80-m w-60-l center pv4 ph3 pa5-ns dib", css(classes.modal))}>
####<h2 className={joinClasses("ma0", css(classes.lineOne))}>
####<h3 className={css(classes.lineTwo)}>{lineTwoText}</h3>
####<a href={buttonLink} className={css(classes.buttonLink)}>
#####<h4 className={joinClasses("pv3 ph4 dib ma0", css(classes.button))}

Each of these classes will now be examined in detail. Atomic CSS classes are in the strings, and Aphrodite CSS-in-JSS (JSS) classes are given functional names (such as classes.button).

Every Atomic CSS classname is linked to the Atomic CSS file where that class is found.

<div className={joinClasses("w-100 center", css(classes.wrapper))}>

  • This is the wrapper <div> element.
  • CSS .w-100 {width: 100%;}
  • JSS wrapper: {maxWidth: "96rem",}

#<div className="relative">

  • This is the second layer of the wrapper <div>.
  • CSS .relative {position: relative;}

##<div className="absolute absolute--fill w-100 h-100">

  • This is the wrapper <div> for the background image, which will fill the entire area.
  • CSS .absolute {position: absolute;}
  • CSS .absolute--fill {top: 0; right: 0; bottom: 0; left: 0;}
  • CSS .w-100 {width: 100%;}
  • CSS .h-100 {height: 100%;}

###<img className={joinClasses("dib w-100 h-100", css(classes.image))} />

  • This is the background image itself, an <img> tag filling 100% of the wrapper.
  • CSS .dib {display: inline-block;}
  • CSS .w-100 {width: 100%;}
  • CSS .h-100 {height: 100%;}
  • JSS image: {objectFit: "cover", objectPosition: "center center",}

##<div className={joinClasses("v-mid ph3 pv4 pv5-m pv6-l relative tc", css(classes.modalWrapper))}>

  • This is a wrapper for the modal.
  • CSS .v-mid {vertical-align: middle;}
  • CSS .ph3 {padding-left: 1rem; padding-right: 1rem;}
  • CSS .pv4 {padding-top: 2rem;padding-bottom: 2rem;}
  • CSS .pv5-m {padding-top: 4rem; padding-bottom: 4rem;} for medium displays
  • CSS .pv6-l {padding-top: 8rem; padding-bottom: 8rem;} for large displays
  • CSS .relative {position: relative;}
  • CSS .tc {text-align: center;}
  • JSS modalWrapper: {color: modalTextColor,}

###<div className={joinClasses("w-80-m w-60-l center ph3 pv4 pa5-ns dib", css(classes.modal))}>

  • This is the modal box itself.
  • CSS .w-80-m {width: 80%;} for medium displays
  • CSS .w-60-l {width: 60%;} for large displays
  • CSS .ph3 {padding-left: 1rem; padding-right: 1rem;}
  • CSS .pv4 {padding-top: 2rem;padding-bottom: 2rem;}
  • CSS .pv5-m {padding-top: 4rem; padding-bottom: 4rem;} for medium displays
  • CSS .pa5-ns {padding-top: 4rem; padding-bottom: 4rem;} for large displays
  • CSS: .dib {display: inline-block;}
  • JSS modal: {backgroundColor: modalBackgroundColor,}

####<h2 className={joinClasses("ma0", css(classes.lineOne))}>

  • This is the first line of heading text, displayed in a large font, with no margin.
  • CSS .ma0 {margin: 0;} 
  • JSS lineOne: {fontSize : "3rem",}

####<h3 className={css(classes.lineTwo)}>{lineTwoText}</h3>

  • This is the second line of heading text and contains no Atomic CSS styles. It is configured to be not bold and to have a larger-than-normal line-height for spacing.
  • JSS lineTwo: {fontWeight : "normal", lineHeight : "1.5rem",}

####<a href={buttonLink} className={css(classes.buttonLink)}>

  • This is the link for the button, with a dynamic transition of the text color on hover.
  • JSS buttonLink: {color: buttonTextColor, transition: "color 0.15s ease-in 0s",}

#####<h4 className={joinClasses("ph4 pv3 dib ma0", css(classes.button))}

  • This is a simple button using the selected background color, with no margin.
  •  CSS .ph4 {padding-left: 2rem; padding-right: 2rem;}
  •  CSS .pv3 {padding-top: 1rem; padding-bottom: 1rem;}
  •  CSS .dib {display: inline-block;}
  •  CSS .ma0 {margin: 0;}
  •  JSS button: {backgroundColor: buttonBackgroundColor, fontWeight: "bold",}

Note that CSS and JSS are written differently. The CSS is hyphenated, but the JSS is written in camelCase. This is because JavaScript object property names cannot contain hyphens.

Having seen how the Block is constructed, it is time to finish assembling the custom Block by adding the custom styles file and writing unit tests.

Update /src/getStyles.js

Open up /src/getStyles.js from the Hero Image Modal Block in your IDE or text editor.

Replace the contents of the file with this following code:

export const getStyles = (blockConfig) => {
const {
modalBackgroundColor,
modalTextColor,
buttonBackgroundColor,
buttonTextColor,
} = blockConfig
return {
wrapper: {
maxWidth: "96rem",
},
image: {
objectFit: "cover",
objectPosition: "center center",
},
modalWrapper: {
color: modalTextColor,
},
modal: {
backgroundColor: modalBackgroundColor,
},
lineOne: {
fontSize: "3rem",
},
lineTwo: {
fontWeight: "normal",
lineHeight: "1.5rem",
},
buttonLink: {
color: buttonTextColor,
transition: "color 0.15s ease-in 0s",
},
button: {
backgroundColor: buttonBackgroundColor,
fontWeight: "bold",
},
}
}

This file simply lists the CSS classes for Aphrodite discussed in the last section.

The user-configurable text and background colors are destructured from the Block’s props and assigned to their individual classes.

Next, you will update the unit tests for the custom Block.

Update /__tests__/Block.spec.js

The next step in making the Hero Image Modal Block is publishing your custom Block, which will make it available to use in your VOLT Store.

In order to publish a custom Block with Element, you need to get all the Block’s tests passing.

Open up /__tests__/Block.spec.js and replace the code entirely:

import React from "react"
import { mount } from "enzyme"
import {
mockUtils as utils,
joinClasses,
} from "@volusion/element-block-utils/test-utils"
import { block as Block, defaultConfig } from "../src"

let props
describe("The Block", () => {
beforeEach(() => {
props = {
data: {},
utils,
joinClasses,
queryParams: {},
}
})
it("renders without errors", () => {
mount(<Block {...props} />)
})
describe("when there is no custom data", () => {
it("should render the block with the default content", () => {
const wrapper = mount(<Block {...props} />)
const { lineOneText, lineTwoText, buttonText } = defaultConfig
expect(wrapper.text()).toBe(lineOneText + lineTwoText + buttonText)
})
})
describe("when given custom data", () => {
it("should render the block using the custom data", () => {
const customText = "Custom Block Text"
const wrapper = mount(
<Block
{...props}
lineOneText={`${customText}1`}
lineTwoText={`${customText}2`}
buttonText={`${customText}3`}
/>
)
expect(wrapper.text()).toBe(`${customText}1${customText}2${customText}3`)
})
})
})

To run the tests, enter the terminal command npm run test:

npm run test

This code only tests that the three heading lines are correctly displayed when they are passed using the default props or as custom props.

To learn how to test that the CSS is being shown (rendered) correctly, please read the previous article Unit Testing CSS in Custom Blocks.

To test the Google AMP (Accelerated Mobile Pages) version of the Block, copy the same code into /__tests__/AMP.spec.js, but change line 14 from “utils: {},” to:

utils: { ...utils, isAmpRequest: true },

This change will cause that unit test to render the AMP version of the Block instead of the regular version.

Once you are finished with both test files, you can build and publish the Hero Image Modal Banner for use in the VOLT Store.

Inspect the Block locally

Before publishing, it is a good idea to inspect your custom Block locally.

Start the local development server using the npm run start (or npm start) command:

npm run start

This should open up a new browser window so you can inspect the custom Block. If it doesn’t open a window, then browse to http://localhost:4000/ to check out the Hero Image Modal Block.

The Block should show the default props (from /src/configs.js).

Now would be a good time to modify the local props (defined in /local/index.js) to test the functionality of the custom Block, if you are so interested.

Build and publish the new Block

Once you are done testing the Block with local props, you are ready to publish the custom Block so that you can try it out in VOLT’s Site Designer.

First, terminate the local server (npm start) using Ctrl+C to stop the running process.

You must build the Block using the npm run build command in order to publish a new Block from Element to VOLT’s Site Designer:

npm run build

Next, you will publish the Block using the Element CLI, using the element publish command:

element publish -n "Hero Image Modal Block"

Use the required -n (“name”) flag to set the name of the Block. Note that the name of the Block needs to be in quotes. The Element CLI will next prompt you to select the category for this Block using the arrow keys. Choose Hero Image Banners and then hit the Enter key.

You will see a warning notice that no image exists for “thumbnail.png” because you have not yet made a thumbnail image for the custom Block to display in VOLT’s Site Designer.

For instructions on adding a thumbnail image, please refer to the YouTube video (4 mins) How to Create a Thumbnail for Your Block | Element Tutorial | VOLT Resource Center or the documentation available for the Element CLI’s publish command.

Create and edit a new theme in VOLT’s Site Designer

Having published the Hero Image Modal Block, you can create a new theme to work with in VOLT’s Site Designer to try out the Block. Themes house all the Pages in your VOLT store, and a new theme will give you an isolated workspace for testing.

Click the + Create new theme link in VOLT’s Site Designer (to the right of Inactive Themes) to open a new theme. Enter “Hero Image Block Test Theme” as the Theme Name, then click the Create button at the bottom-right of the dialog box.

If VOLT’s Site Designer opens up to the store’s active theme, first click Change Theme at the top-left of the screen next to the current theme name to go back to the screen where you can create a new theme.

The homepage of the new theme will be largely empty. By default, the homepage shows just the Header at top and the Footer at bottom.

To add the new Hero Image Modal Block to the homepage, first click the plus sign (+) above where it says Add Block, then click Hero Image Banners in the sidebar that appears at left.

In that list, find the name of the Block that you specified with the element publish command using the -n “Name” flag.

Click the Add Block button to add the Hero Image Modal Block. To change the text, link, image, or colors in the custom Block, select the newly-added Block for editing by clicking on it.

You can preview the new homepage using the Preview button, located at the top-left of VOLT’s Site Designer. This will take you to a preview version of the VOLT store, such as:

https://preview-your-volusion-store.myvolusion.com/ 

The Publish button in VOLT’s Site Designer will not yet show the custom Block on the published (live) version of the VOLT Store. That’s because the new custom Block is still in “Staging” (or development). The next section describes releasing the Block from staging to production.

Update the Block and release it to production

When you have made changes to the Hero Image Modal Block that you are ready to test in VOLT’s Site Designer, you need to rebuild the Block with npm run build, and then update it using the element update command:

npm run build
element update

This will make a new minor version. Minor versions automatically update the Block inside VOLT’s Site Designer as well as in all VOLT stores using that Block.

For more information, please refer to How To Release A Minor Version or How To Track Block Versions from the Element Platform Documentation.

Up until this point, the Block has been in staging, only visible on the preview version of your store in VOLT’s Site Designer, so it is time to release it to production.

To release the Block and make it live on all public VOLT Stores using the Block, use the element release terminal command with the -n “Notes” flag:

element release -n "The Release Notes for this Version"

Note that the release notes need to be in quotes. Release notes are optional but highly recommended.

This command will ask you to confirm on the command line using text input “Y” for yes or “n” for no. That’s because releasing the Block takes effect immediately on the stores that have your Block installed.

It is recommended to track the version release using Git at the command line:

git commit -am "Version 1.0"
git tag 1.0

The element release command will release Version 1 (V1) of the custom Block. For more information, please refer to the Element CLI’s release command from the Element Platform Documentation.

Conclusion

A Hero Image Modal Block is a useful way of understanding how Atomic CSS classes can be combined to make a hero image banner with a modal box effect.

VOLT’s developmental flexibility allows you to quickly and easily make a complex design like the Hero Image Modal Block built in this article.

This article primarily focused on Atomic CSS classes from the spacing.css and width.css Atomic CSS stylesheets in order to build the Hero Image Modal Block.

The whole list of Element’s built-in Atomic CSS classes is available in the Element Platform Documentation.

This article briefly touched on using Aphrodite for styles that are not handled by Atomic CSS. For more information on using Aphrodite classes in Element, please refer to the article How To Style a Block With Aphrodite , also available in the Element Platform Documentation.

The call-to-action button for this example was kept simple on purpose. Element actually offers a Button component as part of its element-components GitHub library. The components from that repository are injected by default into all Element Blocks, allowing users to style the buttons using the Design Settings feature inside VOLT’s Site Designer.

For a production-ready custom Block, you may want to include more tests to ensure reliability when making future changes. For help doing so, please refer to the previous articles on Unit Testing a Custom Block and Unit Testing the CSS in a Custom Block.

This article used only a few Element Proptypes, the settings for props that will be configured by the user of the Block in the VOLT Store. For a tutorial mixing together more Element Proptypes, please refer to the previous article on Mixing Element Proptypes to Make a Sale Banner. You may also want to read the article Element Proptypes Explained.

Making a Hero Image Modal Block is just one example of the power and flexibility of the Element platform. For another tutorial, check out the previous article How to Create a Custom 404 Block Using Element to learn how to make a “Page Not Found” page that displays a list of the VOLT Store’s products.