Creating Responsive Layouts for Components

Responsive web design is a web development approach that creates websites that dynamically adjust their layout and appearance to fit the screen size and orientation of any device, whether it's a desktop computer, tablet, or smartphone. By adhering to responsive design principles and standards, you can facilitate usability, navigation, and accessibility across many different devices.

Understanding Responsive Design

Responsive design is a critical consideration in frontend application development for several reasons:

  • Reach & Inclusivity: Users move between desktop, tablet, and phone. Responsive components ensure every touchpoint is usable without separate applications and codebases.
  • Brand Consistency at Scale: Components that adapt to the page grid keep layouts on-brand across sites, languages, and campaigns.
  • Lower Total Cost: Fewer one-off breakpoints and overrides mean faster delivery, simplified maintenance, and less QA churn.
  • Enhanced User Experience: The styling of the content shifts from device to device. This is particularly important when working with smaller screens (such as smartphones) where the accuracy of a “touch” action is difficult to manage. Content that switches from horizontal to vertical is more readable and facilitates larger areas for triggering calls to action.

With these benefits in mind, let’s take a look at how you can make Liferay pages and applications responsive.

Designing Responsive Layouts

Liferay pages act as containers for content with grids providing the layout. The content can come from a variety of places – web content, fragments, widgets, or client extension components. What’s important to realize is that your component renders within a Liferay page that already has a container and grid. The goal is to fill the space you’re given, not to reinvent the page layout.

With this in mind, there are a few rules of thumb that can be used as a checklist when designing a responsive layout for a component.

  • Always have a wrapper around your component.
  • Make the component's outer container full-width. Don’t set fixed widths on the wrapper for your component.
  • Prefer relative units (%, rem, clamp) over fixed pixel (px) units.
  • Use the theme CSS utility classes (Bootstrap and Clay grid, spacing, display, etc.) to align with the rest of the site's layout and breakpoints.

In order to respect the layout, there are two phases. The first is to set up your component with the full-width component pattern. The second is to determine the internal layout of the component.

Full-Width Component Pattern

The simplest way to ensure that your component occupies the full width of its parent container (the section of the Liferay page where it is being rendered) is to provide a parent that takes up 100% of the width.

<!-- Rendered by your web component -->
<div class="w-100 my-sample-component-container">
  <div class="container-fluid p-0">
  
    <!-- component content goes here -->
  
  </div>
</div>

The outer div here has the 100% horizontal width applied. The second class (my-sample-component-container) is optional; however, it is also a best practice, as it provides a way to target the component either with JavaScript or to scope styles in CSS. Once the container is in place, you can do whatever you want for the component content itself, knowing that the element as a whole will fill the space it has been allocated.

Internal Component Layout

There are three main options for managing a component’s internal layout:

  • Liferay Theme Grid
  • CSS Grid
  • Flexbox

Each of these options has specific use cases and advantages.

Option A: Liferay Theme Grid

The fastest path to designing layouts within components is to use the built-in grid and utilities that come with the Liferay theme. This keeps your component aligned with page breakpoints.

<div class="container-fluid">
  <div class="row g-3">
    <div class="col-12 col-md-6 col-lg-4">
      <div class="card h-100">
        <div class="card-body">
          <h4 class="mb-2">Card Title</h4>
          <p class="mb-0">Content…</p>
        </div>
      </div>
    </div>
    <!-- repeat cols… -->
  </div>
</div>

There are several advantages that come with using this approach.

  • Faster Delivery: Shorter development cycles become possible because these styles are already defined and made available out of the box.
  • Consistency: These same styles are used elsewhere in the product. For certain user groups, like content administrators who move between Liferay features and your solution, this will create a more fluid and consistent user experience.
  • Cascading Changes: All the styles in Liferay are based on primitives (CSS variables), which means changes to the variable value will cascade globally across not just your application but Liferay itself. For example, if mb-2 uses a margin-bottom value of 0.25rem, but you want your margin-bottom to be 0.5rem, you can simply override the value in your theme. Anywhere mb-2 is used, the margin will adjust and align your component with the entirety of the site.

Option B: CSS Grid

When you need more custom control and want to create a masonry-style layout, this is the way to go. This is also an example of where you have CSS that is specific to the component itself rather than being pulled in from a global asset.

<div class="container-fluid">
  <div class="d-grid" style="grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 1rem;">
    <article class="card">
      <div class="card-body">
        <h4 class="mb-2">Grid Item</h4>
        <p class="mb-0">…</p>
      </div>
    </article>
    <!-- more items -->
  </div>
</div>

This solution is somewhat Liferay agnostic. The class d-grid and the inline styling have nothing to do with the theme CSS, but notice that the outer container is still in place to ensure that the component inherits the page spacing.

This option can present challenges in managing grid rendering. It’s best to use the minmax() function in conjunction with autofit for fluid columns. Text sizing and wrapping can also create headaches, so consider using the clamp() function in your font-size definitions to ensure your grid is uniform.

font-size: clamp(1rem, 1vw + .8rem, 1.25rem);

As the name suggests, this option is best suited for content that you want to render in a grid formation. Grid layouts shine in scenarios where you have variable item counts. For example, you want to maintain a 3x3 grid, but you only have 8 items to render. This approach will ensure a clean and consistent layout that handles such cases with ease.

Option C: Flexbox for Rows, Toolbars, and Tiles

Flexbox is the perfect tool for cases where you need to align content in a single row or column and you want it to wrap nicely on small screens.

<header class="container-fluid py-2">
  <div class="d-flex flex-wrap gap-2 justify-content-between align-items-center">
    <h3 class="mb-0">Section Title</h3>
    <div class="d-flex gap-2">
      <button class="btn btn-secondary btn-sm">Action</button>
      <button class="btn btn-primary btn-sm">Primary</button>
    </div>
  </div>
</header>

Flexbox is ideal for navigation bars, toolbars, and simple layouts where content flow is primarily along one axis. Flexbox excels at aligning items, distributing space, and handling responsive behavior within a single direction.

Choosing the Right Option

Each of the options presented is valid, and your choice depends on your specific solution needs. Whenever possible, prefer out-of-the-box Liferay theme CSS when working with layout, spacing, visibility utilities, and typography. They will create a consistent experience for the user and typically require the fewest overrides.

Custom CSS classes are best suited for component internals where you want to prevent “global leaks,” where style classes affect unintended parts of your site or application. The theme CSS also provides utilities to help you define custom classes without creating too much maintenance overhead.

When creating your markup, always do your best to use semantic HTML elements to help screen readers and bots understand the structure. It’s also important to ensure that on smaller screens, where content will wrap, that the order of content rendering continues to make sense. Liferay provides utilities to configure rendering order for these scenarios.

Clarity’s Responsive Design

Clarity has a strict organizational policy requiring all web-based solutions to be responsive. This is particularly important in the case of the Distributor Locator application, as the probability of users accessing this tool from their mobile devices is high. Clarity plans to leverage as many out-of-the-box theme CSS elements as possible. They have also identified several views within their React components that will need one-off custom styling. This means that each of the options that have been presented here will be put into practice based on the location, scope, and type of content that is being rendered.

Conclusion

Building responsive components in Liferay begins with adopting a full-width pattern to respect the existing page structure. For internal component layouts, leveraging the built-in theme grid utilities is the fastest path to a consistent user experience across all devices, while custom CSS grid and Flexbox should be reserved for more complex, component-specific designs.

Next, you’ll apply these principles of responsive design to Clarity’s distributor locator app.

loading-knowledge-label