How to Use BootsFaces and PrimeFaces in the Same Project

Posted on Posted in BootsFaces, PrimeFaces

I’ve always promoted BootsFaces as a companion framework for PrimeFaces, but many developers report it’s difficult, if not impossible, to combine these two frameworks. Things are particularly nasty if you’ve already got a (possibly huge) PrimeFaces application. Some developers report that even adding a single BootsFaces component will distort your application’s layout. So I’ve decided to examine the problem more closely and to do something about it. This article sketches how to integrate BootsFaces components into a PrimeFaces application. I’ve also created a project at GitHub demonstrating the idea. Note that this article doesn’t show how to use a PrimeFaces component in a BootsFaces application. Of course, that’s almost the same problem, but the source codes below only consider the first use case.

The root problem: normalizing browser defaults

At first glance, the situation seems to be hopeless. Almost every modern CSS framework resets the browser defaults. That’s good because different browsers have different default values for things like fonts, margins and a lot more. So it’s a good idea to “normalize” these defaults. After that, you know exactly how your browser renders your HTML page.

That’s what Bootstrap does. After removing the comments, the Bootstrap CSS file start with almost 200 lines of code overriding the browser defaults. The most important settings are the font, the size of the font, and the “box-sizing” model. The latter is particularly annoying because it’s different from the box-sizing model of PrimeFaces. In other words: every size definition has a different meaning in BootsFaces and PrimeFaces. This, in turn, causes many incompatibilities at unexpected places.

To my surprise, PrimeFaces does not normalize the browser defaults. That’s bad news for us. It’s easy to correct the layout if you know the normalized settings of both PrimeFaces and Bootstrap. But it’s difficult to correct the settings if one of these frameworks simply uses the browser defaults. Maybe these defaults are documented, but we don’t want to implement different logic for each browser. For instance, browser us different default fonts, and the fonts even differ for the same browser on different operation systems.

How to tackle the problem

I guess you’ve already got an idea how to solve the problem: we’re going to write a CSS file that restores the PrimeFaces default values. For instance, we can restore the default font settings of PrimeFaces using the CSS value initial:

body {
    font-family: inital;
    font-weight: initial;
    font-size: initial;
    line-height: initial;
    color: initial;
    background-color: initial;
    margin:8px;
}

The challenge is to do it in such a way that the BootsFaces components aren’t affected. Luckily, CSS is flexible enough for that.

As it turns out, most incompatibilities between PrimeFaces and Bootstrap can be addressed at the component level. The idea is to reset the general HTML defaults for PrimeFaces and to add a CSS styleClass to each PrimeFaces component that cares about the incompatibilities. If you need to restore the default settings of Bootstrap for some reason, you do the same trick the other way round: define a CSS class setting the Bootstrap default within a particular div. However, you hardly ever need this because most widgets of BootsFaces are wrapped in a form-control div that restores the Bootstrap defaults again.

My first results are encouraging. Until now, I only tried a few PrimeFaces components: input fields, plain text, command buttons, the selectOneMenu with images and the datatable. That’s far from being an exhaustive test, but even this limited test covers many real-world problems. A single, common CSS class called PF is enough to do most of the work. Basically, you can use my CSS file resetBStoPF.css as a starting point. It’ll make your PrimeFaces application almost identical, no matter whether you add BootsFaces or not. The project is still new, so it goes without saying that the CSS file doesn’t solve every problem perfectly. More on that in a minute.

BootsFaces 1.0.1 and below: the ui-widget font size bug

At that point, I should mention that we’ve added a CSS rule that only applies to b:datePicker in BootsFaces. Unfortunately, it also applies to every PrimeFaces widget. It reduces the font size to 85% of its original size. So you have to use a version newer than BootsFaces 1.0.1. At the time of writing, the newest version is a sneak preview version, 1.1.0-SNAPSHOT. You can use this version, but we haven’t tested it thoroughly. Use at own risk. Alternatively, you can apply an antidote, such as

body {
  font-size: 1.1765em;
}

Different box sizing model

A nasty source of incompatibilities between Bootstrap and PrimeFaces is the different box size model. Bootstrap uses the border-box model, while PrimeFaces uses the content-box model. This results in odd sizes, and a lot of minor or major layout glitches. This can be fixed like so:

.pf,
.pf * {
    -webkit-box-sizing: content-box;
    -moz-box-sizing: content-box;
    box-sizing: content-box;
}

Nesting BootsFaces components in PrimeFaces components

Of course, you need to revert this to use a BootsFaces component within a PrimeFaces component, such as the data table or the PrimeFaces panel. But wait, in most cases you don’t. Bootstrap eagerly resets even such a global setting as the box sizing model in each component. Chances are you want to override the Bootstrap margin of the form-group because it causes BootsFaces input fields to be badly aligned with PrimeFaces widgets:

Adding a CSS class solves the problem:

.nest-bf-in-pf .form-group {
    margin-bottom:0px;
}
<p:dataTable var="person" value="#{bean.muchedumbre}">
    <p:column headerText="First name" styleClass="nest-bf-in-pf">
        <b:inputText value="#{person.firstName}" 
                     placeholder="first name" 
                     tags="true"/>
    </p:column>
    <p:column headerText="Last name">
        <p:inputText value="#{person.lastName}" 
                     placeholder="last name"/>
    </p:column>
</p:dataTable>

This example also shows that there are still minor differences, such as the border of the input fields. Whether you want to align that to the Bootstrap style or to the PrimeFaces style, is up to you. The CSS file should address both options. For instance, you could define classes like alignLayoutToPrimeFaces and alignLayoutToBootstrap.

Your help matters!

At StackOverflow.com, Kukültje mentioned that it’s a lot of work to solve every incompatibility, which is something “you probably don’t want to to”. That’s true. But if we turn it into a community effort, I’m sure the problem can be solved in no time. I’d like to ask you to check out my CSS files, play around with it, run into problems, and to report back. Of course, I’d appreciate if you’d analyze the problem or even sent a pull request because currently, I don’t have that much time to spare. But every bit of help matters. Opening a bug report on the project’s bug tracker is a great first step to improve things.

Integrating the solution into BootsFaces

On the long run, I’d like to integrate the solution into BootsFaces. But before that I want to gather more data about the problem.

Wrapping it up

Among the developer community, there’s a lot of pessimism about combining PrimeFaces and Bootstrap (or BootsFaces, FWIW). However, I believe this pessimism is premature. Granted, there are a lot of challenges. However, I’m sure a joint community effort can solve these obstacles quickly.


Dig deeper

the demo project at GitHub


4 thoughts on “How to Use BootsFaces and PrimeFaces in the Same Project

  1. Hi, do you have some problems with the PrimeFaces selectOneMenu cascade into modal of BootsFaces.
    I have spent 4 days on this issue. The PrimeFaces selectOneMenu doesn’t work inside a BootsFaces modal 🙁

    1. Would you mind being a bit more specific about what’s broken? I’ve tried to reproduce your bug, and I’ve seen two problems. The layout of the PrimeFaces <p:selectOneMenu > is broken. This is probably fixed with the hints of the article. If not, please send a pull request to my GitHub repository. The other problem is that the panel showing the select options doesn’t show. You can fix this with a simple (and ugly) CSS stylesheet:

      <style>
      .ui-selectonemenu-panel { 
        z-index:2004 !important;
      }
      </style>
      

Leave a Reply

Your email address will not be published.