This is the documentation for concrete5 version 5.6 and earlier. View Current Documentation

Style Guide For 5.5

Styling Add-Ons For 5.5

Learn how to make sure your blocks, applications and themes look and work great in concrete5.5 and above.

Notes on 5.6

The big difference here is that 5.6 actually uses bootstrap 2. So all of its styles are available to you. For dashboard pages, if you class your elements according to the form css in particular, you will end up with dashboard pages consistent with the core and most add-ons.

Before You Start

Familiarize yourself with the table styling, form styling, type styling and grid sections from Twitter Bootstrap. It's a good idea to open that up in a new tab or window. For concrete5 specific stuff, everything in the dashboard uses these conventions. So if you open up the dashboard you can follow along with your browser’s “inspect element” tool to see how bootstrap applies its styles while you read this.

Note: concrete5.5 uses Bootstrap version 1.4. Features and revisions introduced in subsequent releases of Bootstrap may not be available. Please consult the following resources for learning more about Bootstrap 1.4 specifically:

Bootstrap 1.4 Documentation (mirror 1)

Bootstrap 1.4 Documentation (mirror 2)


Any time you want to use the styles found in Twitter Bootstrap, you have to ensure that a div with the class “ccm-ui” wraps around whatever you want to style. Loader::helper('concrete/dashboard') will set up a dashboard pane for you that will include this class automatically. Its usage is introduced below under “Dashboard Panes”. Dashboard pages should only have one pane per page.

Follow bootstrap’s conventions for your form elements.


If it launches something new, or saves an optional item, the button should be inline and grey.

If the button saves an entire form, it should be a blue button in the footer labeled “Save” “Add” or “Go”. The footer concrete5 uses has the class “ccm-pane-footer”.

All links or buttons should have a “btn” class. The buttons found in Loader::helper(‘concrete/interface’) should already have the class applied for you.

Dashboard panes ought to use the class “btn error” on any delete buttons to color them red.

Dashboard panes ought to use “btn primary” for any update/add buttons.


Avoid using tables to position form elements. Use the bootstrap form layouts and grids. Tables are fine for tabular data. Feel free to get sassy with the “zebra-striped” class on a table.


In general, you shouldn't have to do too much with blocks to get them to appear acceptably. Certain styles have been retained for backward compatibility. If, however, your blocks look unacceptable in add or edit mode, it's simple to get the Twitter Bootstrap styles to apply to them (which lets you use their form styling, label styling, input elements, etc...) Simply add this class variable to your block's controller:

protected $btWrapperClass = 'ccm-ui';

This will wrap your block's forms in a div with the "ccm-ui" class, which will activate the new styling.

Dashboard Panes

When you need to open the primary dialog on any page, use this function:

$h = Loader::helper('concrete/dashboard');
print $h->getDashboardPaneHeaderWrapper($title, $helpText,$columnSpanClass, $includeDefaultBody, $navigatePages = array(),$upToPage = false);

By default, $columnSpanClass and $includeDefaultBody can be left blank. If $columnSpanClass is blank, the dialog will span the 960 width. $columnSpanClass can be any valid string for bootstrap’s grid system: “span10 offset3”, for example. If $includeDefaultBody is left blank, the default body (which does NOT include a button footer but does include the body) will be used.

An example of not including the default body and making a slightly smaller dialog can be found on the sitemap page:

print $h->getDashboardPaneHeaderWrapper(t('Sitemap'), t('The sitemap allows you to view your site as a tree and easily organize its hierarchy.'), 'span14 offset1', false);

If you don't include a default body, you need to add

  <div class="ccm-pane-body">

immediately below your content. Then, when you want to add a footer, you need to add

  <div class="ccm-pane-footer"></div>

after that.

If you want to manually control which pages show up in the pane’s drodown navigation menu (indicated by a caret), populate the $navigatePages array with an array of page objects. If you pass a page object to $upToPage you can control whether there is a “Back to” link under the caret navigation menu. See the Systems & Settings section for examples of both of these. In many cases they can be left blank.

Once you are finished with the content in a primary dialog, either include:

 print $h->getDashboardPaneFooterWrapper();


 print $h->getDashboardPaneFooterWrapper(false);

You need to use "false" if you used "false" for $includeDefaultBody above.

Dashboard panes ought to use the “ccm-pane-footer” class around any buttons they use. For examples of this, try setting up a page type for composer and writing a draft, or adding a file set. Examples of Dashboard Panes:

  • Pane with buttons: Dashboard > System & Settings > Editing > Languages
  • Add File Set (also has an example of a search bar)


Inline help is fine if it is terse and required. Your time is better spent on the help drop down copy.

  • Bad inline help: "This setting controls what this add-on does. It is a number and it will go to the internet. So think about it."
  • Bad help dropdown: "Fill in teh form, hit save."

  • Good inline help: "Sane values are between 1 and 42."

  • Good help dropdown: "Choose which pagetype to send to Facebook to update your status. Pages can optionally use a custom attribute with the handle “fb_status” to set the status text."
Loading Conversation