Pages

Wednesday, May 18, 2022

Collapsible Card with 0% javascript

Introduction

In this post, we will create collapsible card in HTML/CSS. The main challenge is to don't use any javascript code.

Example:

See the Pen Collapsible Card by mirushaki (@mirushaki) on CodePen.

HTML Structure

The component consist of 2 parts: the title and the body. Clicking on the title must toggle the visibility of the body. To achieve this behavior in pure HTML, we have to use specific HTML tags as building blocks of our component. These tags are: <details> and <summary>

The <details> tag specifies additional details that the user can open and close on demand. It acts as a wrapper.

The <summary> specifies a visible title for the details. It has to be the direct child of <details> tag. After the tag, there should be valid HTML content which will be visible when clicking on the title. So the structure of our component is:

<details>

  <summary>The Awesome Title</summary>

  <p>This is example body text</p>

</details>

NOTE: Instead of <p> tag, we can put any valid HTML content, including multiple tags after <summary> tag.

This is an example of the following code without any CSS:


See the Pen Collapsible Card - simple by mirushaki (@mirushaki) on CodePen.


Apply CSS Styles

Clicking on the title will toggle the visibility of body content. But there are some points that needs attention. The actual style will be user agent(browser) dependent. To maintain the same appearance between different browsers, we have to customize our component using CSS.

Let's introduce a class "m-card" and apply it to <details> tag. We will put every custom style inside.
Also to maintain proper margins/paddings we need to introduce a body wrapper <div> tag and apply m-card-content class to it. So, the HTML is:

<details class="m-card">

  <summary>The Awesome Title</summary>

  <div class="m-card-content">

          <p>This is example body text</p>

  </div>

</details>

Let's customize the title/header of our component, so we are styling <summary> tag of our component:

details.m-card > summary {

  font-size: 1.3rem;

  background-color: #ddd;

  padding: .5em;

  cursor: pointer;

}

The selector is details.m-card > summary, which means we are selecting every <summary> tag, which is the direct child of <details> tag where <details> tag has class named "m-card".
Let's make the title a little bit (1.3 times) bigger then default page text.

Note: I'm using "rem" units for font sizes. Here is a great video explaining different CSS units:
background-color and  padding styles are self-explanatory and finally we are setting cursor: pointer to display "pointer" cursor on hover. It makes component easier to use: the title is clickable and user is encouraged to click the content.


Now, let's write some styles for body content:

details.m-card > div.m-card-content {

  padding: .5em;

  border: 2px solid #ddd;

}

The selector is details.m-card > div.m-card-content, which means we are selecting every <div> tag, which has class named "m-card-content" and which is the direct child of <details> tag where <details> tag has class named "m-card". The actual sytles are self-explanatory.

But, what about the marker?

Good news, we can apply CSS styles to marker as well. By default, in Google Chrome marker is displayed as black triangle. We can use eye-catching icons instead!

The idea is the following: <summary> tag has pseudo element ::marker. We can apply limited number of properties to ::marker pseudo element. One of them is the "content" property.

CSS "content" property can accept UTF8 text as well as HTML emojis, Font awesome icons, Bootstrap icons, etc. So it's really handy and flexible.

See more on ::marker selector

Let's use ➕ and ➖ HTML emojis. Please, leave a comment if you are interested in how to use FontAwesome icons. When card is closed, we should display ➕ . When card is opened, we should display ➖.

details.m-card > summary::marker {
  content: "\2795";
}

details[open].m-card > summary::marker {
  content: "\2796";
}

When the card is opened, the <details> tag has "open" HTML attribute. That makes possible to distinguish between opened/closed states in CSS styles. You may wonder, what does 2795 and 2796 mean? These are hexadecimal codes for  HTML emojis. We need unicode escaping when using these codes as the values of "content" property, thereby we use "\" and then the hexadecimal code.

Here is the list of HTML emojis

See the Pen Collapsible Card by mirushaki (@mirushaki) on CodePen.

What about transitions and animations?

There are some workarounds to achieve transitions / animations using only CSS, but none of them works ideally. Thereby, I'll not post them in this blog.

This is just a simple component in only CSS / HTML for practicing. It is designed for very simple web-sites. It is always recommended to use well-known bootstrap components or web-component libraries to achieve maximum compatibility and avoid custom code.
However, if javascript is disabled, this workaround might become handy.

No comments:

Post a Comment