Start a conversation

Styling custom Handlebars components

You can style custom Handlebars components in two ways: manually or via a GraphQL mutation.

There are two file locations available for adding custom styling to your Handlebars components, depending on if you want to make this styling available for a specific component or all of your components.

  • Specific Component: A .module.pcss file
  • All Components: A common mixin file
Note
The .pcss file type stands for PostCSS, a new style format supported by Khoros Community. Post Custom Style Sheet (PostCSS) files introduce Syntactically Awesome StyleSheet (SaSS) support to your components. You can find more information about PostCSS in its official documentation.

How Aurora processes and stores the Post CSS for a component

After you have restarted your community or cleared the component cache and then make your first request to Aurora that has a handlebars component, Aurora makes a GraphQL API call to fetch the component content which includes the PCSS file.

Community returns a version of the .module.pcss file with the component call response that has the content of all the mixins referenced in the .pcss file (in the @import 'mixins/_mixin_name.pcss' format) placed in the places included in the .module.pcss file.

Aurora uses the content of the .module.pcss file from the Community and processes it via a PostCSS filter which compiles it into CSS and changes the locally-scoped CSS into globally-scoped CSS. This modified CSS, as well as a map of local-scoped CSS class names to global-scoped CSS class names, are stored in the Aurora components cache alongside the component in the Aurora components cache.

Then, when the component is rendered, it adds the CSS to a style tag under the head tag if it is not there already. It uses the map to convert the component markup's local-scoped CSS classes into the correct global-scoped CSS classes.

Here is an example of what the .module.pcss file might look like for the TopMembers example component:

@import "mixins/_avatar.pcss";
@import "mixins/_panel.pcss";
@import "mixins/_screenreader.pcss";

:root {
  --gold-bg: #ffda61;
  --gold-text: #4d3b01;
  --silver-bg: #b8bbbf;
  --silver-text: #24282e;
  --bronze-bg: #ffccb8;
  --bronze-text: #3b1c10;
}

.list {
  display: flex;
  flex-direction: column;
  row-gap: 10px;
  padding-left: 0;
  margin: 0;
  list-style: none;
}

.user {
  display: flex;
  align-items: center;
  padding: 15px 20px;
  column-gap: 15px;
  color: var(--lia-bs-body-color);
  @include panel-defaults();

  &-name {
    font-size: var(--lia-bs-h5-font-size);
    font-weight: var(--lia-bs-font-weight-normal);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  &:hover {
    color: currentColor;

    .badge-wrap {
      rotate: 10deg;
    }
  }
}

.avatar-wrap {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  @include avatar-size(30);

  .avatar-img {
    border-radius: var(--lia-avatar-border-radius);
    background-color: var(--lia-bs-gray-400);
    overflow: hidden;
    display: block;
    background-size: contain;
    height: 100%;
    width: 100%;
  }
}

.list-item {
  &:first-child .user {
    background-color: var(--gold-bg);
    color: var(--gold-text);

    &-name {
      font-size: var(--lia-bs-h3-font-size);
    }
    .avatar-wrap {
      @include avatar-size(50);
    }
  }
  &:nth-child(2) .user {
    background-color: var(--silver-bg);
    color: var(--silver-text);
  }
  &:nth-child(3) .user {
    background-color: var(--bronze-bg);
    color: var(--bronze-text);
  }
}

.badge-wrap {
  margin-left: auto;
  transition: rotate var(--lia-timing-normal) var(lia---lia-timing-function);

  .badge {
    @include avatar-size(50);
  }
}

.congrats {
  margin: 20px 0 0;
  color: var(--lia-bs-text-muted);
  font-size: var(--lia-bs-font-size-sm);
}

Since this imports mixins named _avatar.pcss, _panel.pcss, and _screenreader.pcss, you must also create these files with the same names under the components/styles/mixins directory.

@mixin avatar-size($size) {
  width: var(--lia-icon-size-#{$size});
  height: var(--lia-icon-size-#{$size});
  min-width: var(--lia-icon-size-#{$size});
  min-height: var(--lia-icon-size-#{$size});
}
@mixin panel-defaults() {
  background-color: var(--lia-panel-bg-color);
  box-shadow: var(--lia-panel-box-shadow);
  border: var(--lia-content-item-border);
  border-radius: var(--lia-panel-border-radius);
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

Here is what the transformed CSS would look like:

<style type="text/css">
.custom_widget_TopMembers_sr-only_17ufj_15 {
  position: absolute;
  width: 0.0625rem;
  height: 0.0625rem;
  padding: 0;
  margin: -0.0625rem;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

:root {
  --gold-bg: #ffda61;
  --gold-text: #4d3b01;
  --silver-bg: #b8bbbf;
  --silver-text: #24282e;
  --bronze-bg: #ffccb8;
  --bronze-text: #3b1c10;
}

.custom_widget_TopMembers_list_17ufj_37 {
  display: flex;
  flex-direction: column;
  grid-row-gap: 0.625rem;
  row-gap: 0.625rem;
  padding-left: 0;
  margin: 0;
  list-style: none;
}

.custom_widget_TopMembers_user_17ufj_46 {
  display: flex;
  align-items: center;
  padding: 0.9375rem 1.25rem;
  grid-column-gap: 0.9375rem;
  -moz-column-gap: 0.9375rem;
  column-gap: 0.9375rem;
  color: var(--lia-bs-body-color);
  background-color: var(--lia-panel-bg-color);
  box-shadow: var(--lia-panel-box-shadow);
  border: var(--lia-content-item-border);
  border-radius: var(--lia-panel-border-radius);
}

.custom_widget_TopMembers_user-name_17ufj_1 {
  font-size: var(--lia-bs-h5-font-size);
  font-weight: var(--lia-bs-font-weight-normal);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.custom_widget_TopMembers_user_17ufj_46:hover {
  color: currentColor;
}

.custom_widget_TopMembers_user_17ufj_46:hover .custom_widget_TopMembers_badge-wrap_17ufj_64 {
  rotate: 10deg;
}

.custom_widget_TopMembers_avatar-wrap_17ufj_70 {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  width: var(--lia-icon-size-30);
  height: var(--lia-icon-size-30);
  min-width: var(--lia-icon-size-30);
  min-height: var(--lia-icon-size-30);
}

.custom_widget_TopMembers_avatar-wrap_17ufj_70 .custom_widget_TopMembers_avatar-img_17ufj_77 {
  border-radius: var(--lia-avatar-border-radius);
  background-color: var(--lia-bs-gray-400);
  overflow: hidden;
  display: block;
  background-size: contain;
  height: 100%;
  width: 100%;
}

.custom_widget_TopMembers_list-item_17ufj_88:first-child .custom_widget_TopMembers_user_17ufj_46 {
  background-color: #ffda61;
  background-color: var(--gold-bg);
  color: #4d3b01;
  color: var(--gold-text);
}

.custom_widget_TopMembers_list-item_17ufj_88:first-child .custom_widget_TopMembers_user-name_17ufj_1 {
  font-size: var(--lia-bs-h3-font-size);
}

.custom_widget_TopMembers_list-item_17ufj_88:first-child .custom_widget_TopMembers_user_17ufj_46 .custom_widget_TopMembers_avatar-wrap_17ufj_70 {
  width: var(--lia-icon-size-50);
  height: var(--lia-icon-size-50);
  min-width: var(--lia-icon-size-50);
  min-height: var(--lia-icon-size-50);
}

.custom_widget_TopMembers_list-item_17ufj_88:nth-child(2) .custom_widget_TopMembers_user_17ufj_46 {
  background-color: #b8bbbf;
  background-color: var(--silver-bg);
  color: #24282e;
  color: var(--silver-text);
}

.custom_widget_TopMembers_list-item_17ufj_88:nth-child(3) .custom_widget_TopMembers_user_17ufj_46 {
  background-color: #ffccb8;
  background-color: var(--bronze-bg);
  color: #3b1c10;
  color: var(--bronze-text);
}

.custom_widget_TopMembers_badge-wrap_17ufj_64 {
  margin-left: auto;
  transition: rotate var(--lia-timing-normal) var(lia---lia-timing-function);
}

.custom_widget_TopMembers_badge-wrap_17ufj_64 .custom_widget_TopMembers_badge_17ufj_64 {
  width: var(--lia-icon-size-50);
  height: var(--lia-icon-size-50);
  min-width: var(--lia-icon-size-50);
  min-height: var(--lia-icon-size-50);
}

.custom_widget_TopMembers_congrats_17ufj_119 {
  margin: 1.25rem 0 0;
  color: var(--lia-bs-text-muted);
  font-size: var(--lia-bs-font-size-sm);
}
</style>

Here is what the component markup would look like transformed:

<ul class="custom_widget_TopMembers_list_17ufj_37">
  <li class="custom_widget_TopMembers_list-item_17ufj_88">
    <a class="custom_widget_TopMembers_user_17ufj_46" aria-label="Member John" href="/users/John/2">
      <span class="custom_widget_TopMembers_avatar-wrap_17ufj_70">
        <img src="https://hobbyist.qa.lithium.com/t5/s/hobbyist/images/dS0yLXpTb3ViYg?image-coordinates=0%2C34%2C331%2C365" alt="John's avatar" class="custom_widget_TopMembers_avatar-img_17ufj_77" aria-hidden="false" style="max-width:100%;">
      </span>
      <span class="custom_widget_TopMembers_user-name_17ufj_1">John</span>
      <span class="custom_widget_TopMembers_badge-wrap_17ufj_64">
        <img src="https://hobbyist.qa.lithium.com/t5/s/hobbyist/m_assets/components/TopMembers/assets/badge.png" class="custom_widget_TopMembers_badge_17ufj_64" alt="Image of a 1st place badge" style="max-width:100%;">
        <span class="custom_widget_TopMembers_sr-only_17ufj_15"> First Place Winner </span>
      </span
Choose files or drag and drop files
Was this article helpful?
Yes
No
  1. ATLAS

  2. Posted
  3. Updated

Comments