Bootstrap 4 with Phoenix. Customizing

Hello, I have succesfully integrated Bootstrap 4 with my Phoenix app. This is my app.scss.

// FontAwesome stuff
$fa-font-path: "../fonts";
@import "font-awesome";

// Bootstrap
@import "bootstrap";

How do I customize the theme for bootstrap? For example, I was looking through the source code and found this:

$theme-colors: (
  primary: $blue,
  secondary: $gray-600,
  success: $green,
  info: $cyan,
  warning: $yellow,
  danger: $red,
  light: $gray-100,
  dark: $gray-800
) !default;

I tried to customize the values by adding the following code above @import "bootstrap"

$theme-colors: (
primary: $violet,
secondary: $gray-600,
success: $green,
info: $cyan,
warning: $yellow,
danger: $red,
light: $gray-100,
dark: $gray-800
);

(I changed the primary color)

But it doesn't work as there's no such variable as `$violet` since this is before I import bootstrap. Is this just an issue with Bootstrap or that Bootstrap is just bad for customization, or am I doing something seriously wrong?
2 Likes

Rather you need to import β€˜just’ the color definition file from bootstrap before you use it (not the whole bootstrap).

Or just use the RGB codes instead.

Or define the color names yourself.

Whichever. ^.^

1 Like

I’m on the phone right now so haven’t verified this, but can you try importing the _variables.scss file before redefining the variables and then importing bootstrap at the end?

2 Likes

I think you have to also install and enable the brunch sass-plugin

Also, I don’t think $violet is a predefined variable.
These are the only colors I can find in _variables.scss (Bootstrap v4.0.0-beta)

$blue: #007bff !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #dc3545 !default;
$orange: #fd7e14 !default;
$yellow: #ffc107 !default;
$green: #28a745 !default;
$teal: #20c997 !default;
$cyan: #17a2b8 !default;

So you’d need to define that somewhere.

I have a demo repo up going through the steps:

I found it easiest to use app.scss as your entry point, and pull in your customized sass (such as _custom.scss) files into that.
I also found the order important, as you want to import _custom.scss before the rest of the bootstrap scss files.

If you really wanted to cut down on the final size, you can also use something like postcss-brunch and a plugin like uncss-brunch to strip your pages of unused CSS.

1 Like

I have tried to import the variables.scss files before bootstrap. It gives this compile error:

        node_modules/bootstrap/scss/_variables.scss:168 Error:
argument `$color` of `darken($color, $amount)` must be a color

I searched this up and found that I am supposed to import functions.scss file before variables so I did. Now it compiles, but it just doesn’t work.

Yeap. That’s how I setup bootstrap. Also, I meant $indigo hehe. Was pretty late, brain wasn’t functioning at it’s best. The problem here is that in my custom scss file, I can’t just redefine $theme-colors() and use stuff like $indigo, etc. as they don’t exist, since bootstrap was never imported.

Hold up, it appears that it works!

For those who came to this thread looking for an answer, the solution is to do this in your SCSS file:

@import "functions";
@import "variables";

// Custom theme example
$theme-colors: (
  primary: $red
);

// Bootstrap
@import "bootstrap";

Thanks to all those that replied! :slight_smile:

2 Likes

full disclosure: I am a complete Pheonix newbie so this question is understanding my observation found in the repo posted https://github.com/gbih/phoenix1.3-bootstrap4beta-brunch-sass. I noticed in your repo that:

  • brunch-config.js
  • package-lock.json
  • package.json

is located in /assets and not in root as is generated when you run

$ mix phx.new

Can you explain, please?

Basically those assets were moved from root to inside the /assets directory during the change from Phoenix 1.2 to 1.3

More details are here:

Move static assets inside self-contained assets/ directory

New projects now include a root-level assets/ directory, which serves as a self-contained location for your asset builder’s config, source files, and packages. This changer keeps things like node_modules, package.json, and brunch-config.js from leaking into the root of your elixir application. Update your app to the new structure by following these steps:

thank you for coming back @gpb. I have the latest Phoenix 1.3 but generating a new project put the files in the root. Obviously having read the link Chris suggests moving those files. Does that mean the generator is out of date? Again slightly confused.

Here are the versions I am running:

elixir -v
Elixir 1.6.0-dev

mix phx.new --version
Phoenix v1.3.0-rc.2

*If it shows Phoenix v1.2, you can install 1.3 via:
mix archive.install https://github.com/phoenixframework/archives/raw/master/phx_new.ez

I created a test Phoenix 1.3 project via
mix phx.new test --no-ecto

and here is the output of running tree:
tree -L 2

.
β”œβ”€β”€ README.md
β”œβ”€β”€ _build
β”‚   └── dev
β”œβ”€β”€ assets
β”‚   β”œβ”€β”€ brunch-config.js
β”‚   β”œβ”€β”€ css
β”‚   β”œβ”€β”€ js
β”‚   β”œβ”€β”€ node_modules
β”‚   β”œβ”€β”€ package-lock.json
β”‚   β”œβ”€β”€ package.json
β”‚   β”œβ”€β”€ static
β”‚   └── vendor
β”œβ”€β”€ config
β”‚   β”œβ”€β”€ config.exs
β”‚   β”œβ”€β”€ dev.exs
β”‚   β”œβ”€β”€ prod.exs
β”‚   β”œβ”€β”€ prod.secret.exs
β”‚   └── test.exs
β”œβ”€β”€ deps
β”‚   β”œβ”€β”€ cowboy
β”‚   β”œβ”€β”€ cowlib
β”‚   β”œβ”€β”€ file_system
β”‚   β”œβ”€β”€ gettext
β”‚   β”œβ”€β”€ mime
β”‚   β”œβ”€β”€ phoenix
β”‚   β”œβ”€β”€ phoenix_html
β”‚   β”œβ”€β”€ phoenix_live_reload
β”‚   β”œβ”€β”€ phoenix_pubsub
β”‚   β”œβ”€β”€ plug
β”‚   β”œβ”€β”€ poison
β”‚   └── ranch
β”œβ”€β”€ lib
β”‚   └── test
β”œβ”€β”€ mix.exs
β”œβ”€β”€ mix.lock
β”œβ”€β”€ priv
β”‚   β”œβ”€β”€ gettext
β”‚   └── static
└── test
    β”œβ”€β”€ support
    β”œβ”€β”€ test
    └── test_helper.exs

elixir -v
Elixir 1.5.2

mix phx.new --version
Phoenix v1.3.0

ok here is what is weird… looking through my history I typed, and just tested it again

$ mix phoenix.new

β”œβ”€β”€ README.md
β”œβ”€β”€ _build
β”œβ”€β”€ brunch-config.js
β”œβ”€β”€ config
β”œβ”€β”€ deps
β”œβ”€β”€ lib
β”œβ”€β”€ mix.exs
β”œβ”€β”€ mix.lock
β”œβ”€β”€ node_modules
β”œβ”€β”€ package-lock.json
β”œβ”€β”€ package.json
β”œβ”€β”€ priv
β”œβ”€β”€ test
└── web

However, using:

$ mix phx.new

I get the same as you, how weird:

β”œβ”€β”€ README.md
β”œβ”€β”€ _build
β”œβ”€β”€ assets
β”œβ”€β”€ config
β”œβ”€β”€ deps
β”œβ”€β”€ lib
β”œβ”€β”€ mix.exs
β”œβ”€β”€ mix.lock
β”œβ”€β”€ priv
└── test

I am going to start this again - thank you

So, if this is an old β€œdeprecated” method should it not say it is deprecated and suggest using the new command?

Most confusing - following tutorials just makes life that bit harder :frowning:

However @gpb I seriously appreciate you coming back to me.

1 Like

There are some further changes needed for v5 of font-awesome and bootstrap v4 to work together:

  1. Install npm modules:

    $ npm install --save @fortawesome/fontawesome-free-webfonts   # official package
    $ npm install --save-dev sass-brunch copycat-brunch
    $ npm install --save bootstrap jquery popper.js  # NOT bootstrap-sass
    
  2. renamed web/static/css/app.css to web/static/css/app.sccs and adjusted to include:

    // Specify explicitly so you don't get some other packages functions or variables 
    // for example fontawesome also has variables
    
    @import  "node_modules/bootstrap/scss/functions";
    @import "node_modules/bootstrap/scss/variables";
    
    // @import "node_modules/@fortawesome/fontawesome-free-webfonts/scss/variables"; // unlikely to need this
    
    @import "custom_variables";
    
    @import "bootstrap";
    @import "fontawesome";
    @import "fa-solid";
    
    /* Custom Stuff now everything has been defined */
    
    @import "custom";
    
  3. Add sass and copycat options to plugins hash in brunch-config.js:

    sass: {
     options: {
       // tell sass-brunch where to look for files to @import
       includePaths: [
         "node_modules/@fortawesome/fontawesome-free-webfonts/scss",
         "node_modules/bootstrap/scss"
         ],
       // includePaths: ["node_modules/bootstrap/scss", "node_modules/font-awesome/scss"], // tell sass-brunch where to look for files to @import
       precision: 8 // minimum precision required by bootstrap-sass 
     }
    },
    copycat: {
      // copy .../webfonts/* to priv/static/fonts/
      "fonts": [
        "node_modules/@fortawesome/fontawesome-free-webfonts/webfonts"
        ],
      verbose : false
    }
    
  4. Put your customized variables, which can depend on bootstrap variables in web/static/asset/_custom-variables.scss:

       // FontAwesome stuff
       $fa-font-path: "../fonts";
    
       // Custom theme example
       $theme-colors: (
         primary: $red
       );
    
  5. wrap flash messages into conditions in web/templates/layout/app.html.eex:

      <%= unless is_nil(get_flash(@conn, :info)) do %>
        <p class="alert alert-info" role="alert">
          <%= get_flash(@conn, :info) %>
        </p>
      <% end %>
      <%= unless is_nil(get_flash(@conn, :error)) do %>
        <p class="alert alert-danger" role="alert">
          <%= get_flash(@conn, :error) %>
       </p>
      <% end %>

I mixed and matched ideas from the following and fiddled till it worked:

2 Likes