A simple Symfony bundle for defining your application's menus in configuration and rendering them to work with Bootstrap's Navbar component. This bundle supports Bootstrap versions 4 and 5.
$ composer require camurphy/bootstrap-menu-bundle
Your menus are defined in config/packages/bootstrap_menu.yaml
.
Below is a very simple menu called main
with only a single 'Logout' link.
bootstrap_menu:
version: 5 # Optional, defaults to Bootstrap 5
dropdown_active_style: false # Optional, defaults to false
dropdown_item_active_style: false # Optional, defaults to false
menus:
main:
items:
logout:
label: 'Logout'
route: 'app_logout'
Then within your template you can render your menu in a Navbar by passing the name of your menu to render_bootstrap_menu
. This markup is
taken from the Bootstrap Navbar Fixed example. The Bootstrap 4 version is
here
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav me-auto mb-2 mb-md-0">
{{ render_bootstrap_menu('main') }}
</ul>
</div>
</div>
</nav>
Result:
Perhaps your route requires parameters. You can also specify these.
bootstrap_menu:
menus:
main:
items:
backorder_report:
label: 'Backorder Report'
route: 'app_reports'
route_parameters:
id: 'backorder'
If you would instead like to link to an absolute URL, use url
instead.
bootstrap_menu:
menus:
main:
items:
disney:
label: 'Disney'
url: 'https://www.disney.com'
Simply by specifying items
instead of a route
or url
to link to, your menu item becomes a Dropdown. Here's an example where a
'Change Password' and a 'Logout' link are nested below an 'Account' dropdown.
bootstrap_menu:
menus:
main:
items:
account:
label: 'Account'
items:
change_password:
label: 'Change password'
route: 'app_change_password'
logout:
label: 'Logout'
route: 'app_logout'
Result:
Dropdowns can also contain Dividers to separate groups of related menu items.
bootstrap_menu:
menus:
main:
items:
account:
label: 'Account'
items:
change_password:
label: 'Change password'
route: 'app_change_password'
divider:
is_divider: true
logout:
label: 'Logout'
route: 'app_logout'
Result:
Dividers that also contain a label
become Headers.
bootstrap_menu:
menus:
main:
items:
account:
label: 'Account'
items:
password_divider:
is_divider: true
label: 'Password Stuff'
change_password:
label: 'Change password'
route: 'app_change_password'
other_divider:
is_divider: true
label: 'Other Stuff'
logout:
label: 'Logout'
route: 'app_logout'
Result:
Certain parts of the menu may be locked down by role. This following example only allows administrators to change their password.
bootstrap_menu:
menus:
main:
items:
account:
label: 'Account'
items:
password_divider:
is_divider: true
label: 'Password Stuff'
change_password:
label: 'Change password'
route: 'app_change_password'
roles: [ 'ROLE_ADMINISTRATOR' ]
other_divider:
is_divider: true
label: 'Other Stuff'
logout:
label: 'Logout'
route: 'app_logout'
For a user without ROLE_ADMINISTRATOR
they would see:
The reason for this is Bootstrap Menu Bundle intelligently prunes Dropdowns to remove unnecessary Dividers. Because the user is not permitted to see any items between 'Password Stuff' and 'Other Stuff', the 'Password Stuff' Divider is also pruned.
Security can also be configured at a Dropdown level. Perhaps only administrators are allowed to use the 'Users' menu.
bootstrap_menu:
menus:
main:
items:
users:
label: 'Users'
roles: [ 'ROLE_ADMINISTRATOR' ]
items:
user_list:
label: 'Users'
route: 'app_user_list'
new_user:
label: 'New User'
route: 'app_new_user'
You may also hide menu items from users that have a certain role by prefixing the role with an exclamation mark. This will take precedence
over included roles. In the example below, if they have both ROLE_SUPPORT
and ROLE_USER
they will not see the menu item.
bootstrap_menu:
menus:
main:
items:
users:
label: 'Users'
roles: [ '!ROLE_SUPPORT', 'ROLE_USER' ]
items:
user_list:
label: 'Users'
route: 'app_user_list'
Out of the box, top level menu items are given the active
class when the
current route matches the menu item's route. In this example we're on the 'Reports' page.
It's not documented, but the active
class also works on dropdowns and dropdown items. To enable for dropdowns, set dropdown_active_style
to true
in the config.
To enable for dropdown items, set dropdown_item_active_style
to true.