Create a public chat room dropdown in navigation

  • I am back with another simple tutorial to add a dropdown into the main navigation for public chats 🗨

    End result


    First we need to create the navigation item in the ACP at /admin/settings/navigation. Create a new custom route with the settings shown below. Make sure dropdown is enabled and you give the element a class of navigation-chats. You can leave the dropdown items empty since we will populate it dynamically. Don't forget to save the navigation settings.


    Then go to /admin/appearance/customise#custom-js and add the below custom javascript. This will load the publicRooms and populate the dropdown dynamically.

    (async function () {
      if (app.user.uid) {
        const chats = await $.get(`${config.relative_path}/api/user/${app.user.userslug}/chats`);
        const dropdown = $('.navigation-chats .dropdown-menu, .navigation-chats .collapse');    
        chats.publicRooms.forEach((room) => {
          const roomHref = `${config.relative_path}/user/${app.user.userslug}/chats/${room.roomId}`;
          const roomIcon = `<i class="fa ${room.icon}"></i>`;
          dropdown.append(`<li><a class="dropdown-item" href="${roomHref}">${roomIcon} ${room.roomName}</a></li>`); 

    That should be it once you save the custom javascript and reload your forum you should see a new navigation item with your public rooms. ☮

  • ouaa very cool

    Thanks for the trick @baris

    I love this kind of stuff 😉

    EDIT :

    Working perfectly on Desktop but seems to not work on Smartphone @baris 😞 or did i miss something ?

    It's possible to make it work for both (Smartphone an Desktop) ?

  • @DownPW I've updated the instructions in the main post, it should work on both desktop and mobile now. Thanks for reporting.

  • Thanks dude @baris

    Works great know on Smartphone an Desktop 🙂

    Love it !

Suggested Topics

  • 8 Votes
    7 Posts

    @phenomlab very true. A lot of talented people have done some surprisingly cool things with just the custom css panel.

  • 8 Votes
    1 Posts

    Since NodeBB 1.18.6 it is possible to create dropdowns in the navigation ( Before 1.18.6 to accomplish this you would have to use nodebb-plugin-customize to modify the menu template or use javascript to inject the markup after page load.

    In this tutorial I will show you how to create a dropdown navigation item that replaces the default categories link with a dropdown. The final result will look like this:


    First thing to do is to turn the navigation item into a dropdown, to do this head over to, select the categories navigation item and toggle the dropdown option.


    Once this is done you can use the text area below the toggle to add your markup. To create a simple dropdown you would just add a list of dropdown items like so:

    <li><a class="dropdown-item" href="/categories">All</a></li> <li><a class="dropdown-item" href="/category/2/general-discussion">General Discussion</a></li>

    Since you can input html here you can create custom dropdowns. To achieve the same dropdown as the first gif use the below html code, no css is necessary.

    <li><a class="dropdown-item" href="/categories">All</a></li> <li class="dropdown-divider"> <li><a class="dropdown-item" href="/category/2/general-discussion">General Discussion</a></li> <li class="d-flex flex-column"> <a class="dropdown-item" href="/category/3/nodebb-development">NodeBB Development</a> <div class="d-flex flex-column px-4"> <div class="d-flex align-items-center gap-1"> <i class="fa fa-fw fa-caret-right text-primary"></i> <a class="btn-ghost-sm text-sm text-nowrap" href="/category/13/nodebb-blog">NodeBB Blog</a> </div> <div class="d-flex align-items-center gap-1"> <i class="fa fa-fw fa-caret-right text-primary"></i> <a class="btn-ghost-sm text-sm text-nowrap" href="/category/5/feature-requests">Feature Requests</a> </div> <div class="d-flex align-items-center gap-1"> <i class="fa fa-fw fa-caret-right text-primary"></i> <a class="btn-ghost-sm text-sm text-nowrap" href="/category/6/bug-reports">Bug Reports</a> </div> <div class="d-flex align-items-center gap-1"> <i class="fa fa-fw fa-caret-right text-primary"></i> <a class="btn-ghost-sm text-sm text-nowrap" href="">NodeBB Localization</a> </div> </div> </li> <li><a class="dropdown-item" href="/category/7/nodebb-plugins">NodeBB Plugins</a></li> <li><a class="dropdown-item" href="#">...add more as needed...</a></li>

    Modify the links to match your forum categories. To create dividers between sections you can use <li class="dropdown-divider">

    Now you can navigate your categories without going to the home/categories page. 🎊

  • 1 Votes
    5 Posts

    Example of footer bar with this code (and Other) on my dev site V3 harmony :


  • 0 Votes
    3 Posts

    @psizzles said in Looking to create a simple voting application with a live audience:

    Hi All,

    I am looking to create a voting app. for a live demo. The audience will have three choices to pick from a url from their phone.
    Only I will be able to see the overall results submitted. Would it be possible to get the ip addresses of the people who have voted? Is there a sample app. I can reuse?


    Inside of the forum?

  • 2 Votes
    1 Posts
    What is a registration interstitial?

    When a user registers for a new account, they may be presented with an intermediate step (or "intersitial") before the registration is completed. Alternatively, the interstitial can be invoked after registration.

    You may use this opportunity to obtain additional information about the user for your plugin.

    In this tutorial, we'll be updating the Facebook SSO plugin to capture user emails upon registration.

    The filter:register.interstitial hook

    The hook filter:register.interstitial is fired whenever a user registers for a new account. It is also fired if the user session contains a registration object, and in processing the interstitial page itself.

    The hook signature is {data, callback}, and data contains the following:

    userData (Object) The registration data collected so far interstitials (Array) A collection of interstitial objects, which you can append to if necessary. An interstitial object is: template (String) A template served by your plugin that will be included into the interstitial page data (Object) When rendering the above template, any data needed can go here callback (Function [userData, formData, callback]) When the interstitial page is completed, this callback method will be executed, with the form data included in the second parameter

    In the case of Facebook SSO, we want to capture user email addresses because Facebook may not provide the correct email to us (or at all). By looking at the code, we can see that if the email is not present, we create a fake email ending with

    Step 1: Invoking the interstitial

    Upon completion of SSO registration, we save uid and fbid into req.session.registration. Once this object is set in the user session, NodeBB will automatically forward the user to the registration interstitial:

    // Require collection of email req.session.registration = req.session.registration || {}; req.session.registration.uid = user.uid; req.session.registration.fbid =; Step 2: filter:register.interstitial listener

    Now, we will create a new listener to the filter:register.interstitial hook, and have it add an interstitial if the email ends with

    Facebook.prepareInterstitial = function(data, callback) { // Only execute if: // - uid and fbid are set in session // - email ends with "" if (data.userData.hasOwnProperty('uid') && data.userData.hasOwnProperty('fbid')) { user.getUserField(data.userData.uid, 'email', function(err, email) { if (email.endsWith('')) { data.interstitials.push({ template: 'partials/sso-facebook/email.tpl', data: {}, callback: Facebook.storeAdditionalData }); } callback(null, data); }); } else { callback(null, data); } };

    To note, when registering the interstitial (data.interstitials.push...), we define the template as partials/sso-facebook/email.tpl. This tempate is defined in the plugin itself.

    Secondly, the callback calls Facebook.storeAdditionalData. That method is also defined by the Facebook SSO plugin, and handles updating the user email as passed in via the interstitial page.