Setting of active menu item for NavigationMenu does nothing

Hi @Alan_G

Is it possible for Shopify to publish an article or blog on with an example on how to use ui-nav-menu (toggle the status of the nav link) without React? This document is so cryptic and I couldn’t find any examples on how to “migrate” to App Bridge v4 without React.

Hey @Ronald_G - this is great idea, I do agree the documentation there is fairly no-frills. I’ll look into this on my end and see if we can share a blog post/guide with you/other folks who may be interested.

Still digging into this for you @Ronald_G , but I wanted to follow up here to share a resource/confirm things so we can help out a bit better. In the migration docs, we do have a section on the nav menu: link here.

Essentially you’d just need to first include the web components src like this in your app:

Then you’d just need to define your menu items like this:

Home Templates Settings

Just to confirm the blocker with you, is it because App Bridge 4 derives the active nav item from the current URL, you can’t programmatically force an active item? In your current setup, does UJS intercept navigation without updating window.location/history, so the component never sees the new URL? Let me know and I can look into seeing if I’m able to roll up some further examples to share here if that would be helpful. Feel free to ping me here.

Thanks @Alan_G we’ll try to migrate to AppBridge 4 (non-React version) per Migrate your app to Shopify App Bridge .

As for nav menu, we can programmatically force an active item, but we couldn’t do it in AppBridge 3.

Great to hear @Ronald_G! Please do let me know if you hit any blockers during the migration - happy to troubleshoot with you here.

Hi @Alan_G

Hope you are well. We finally are getting back to this after BFCM.

We got app_bridge.js to load. However, we are stuck on some probably simple issues:

  1. The migration guide says to use <s-page> instead of .create, however, where does that code actually code? Since TitleBar and NavigationMenuare outside of our app, it’s not clear where to call these code?

  2. We use Rails UJS and in the past, we do this in order to get session token. Is that still needed anymore?

    var appBridgeUtils = window[“app-bridge”][‘utilities’];
    window.sessionToken = await appBridgeUtils.getSessionToken(app);

    I believe that’s deprecated, but GitHub - Shopify/turbolinks-jwt-sample-app: A sample app made to demo Shopify's Next-Gen Auth flow using Turbolinks still uses AppBridge 2.0. I believe if you don’t pass a session token, we get ShopifyAPI::Errors::InvalidJwtTokenError. Any insight into this?

Hey @Ronald_G, glad to hear you’re back on this after BFCM, sorry about the delayed reply here, I’ve been OOO for the last little bit.

For your first question about where the web components go, you’d generally want want to add <ui-nav-menu> (link here) in your layout file (like application.html.erb or whichever type of layout you’re using) since it’s a global element that should persist across pages. I’d just make sure you have the meta tag with your API key and the App Bridge script in the head (info here), then drop the nav menu in the body. For page-specific stuff like the title bar, could wrap your view content in <s-page> with a title attribute and slot in any action buttons you need, that goes in your individual view templates rather than the layout.

On the session token question, the old getSessionToken(app) pattern is deprecated, but you do still need to pass a token when making requests to your own Rails backend for authentication. I think for this, you would just want to use: await shopify.idToken() which returns the JWT. So your setup could grab that token and include it in the Authorization header when hitting your Rails endpoints. The shopify_app gem should validate it the same way.

To check this, you can open your browser console while in the embedded app and run shopify.idToken().then(console.log) to confirm you’re getting a valid token back.

Let me know if you hit any snags with that or if anything’s unclear - happy to dig deeper on either piece!

Thanks @Alan_G !

Hope you had a great time OOO.

With your help, we were able to implement UJS, NavigationMenu, and partiallyContextualSaveBar (CSB).

However, I’m a little unclear as to how to know when the CSB is shown vs. hidden? Shopify BFS team is requiring that other button like Cancel, Back be disabled or hidden when CSB is shown.

For example, if the CSB has ID = shopify-csb, this doesn’t seem to work.

document.getElementById('shopify-csb').addEventListener('show', () => {
    console.log('CSB showing');
});

Hey @Ronald_G,

Glad to hear things are working better!

For detecting when the Contextual Save Bar is shown vs hidden, the approach you’re using is correct, the ui-save-bar element does support show and hide event listeners. I’m wondering if the issue is likely just a timing one where the element needs to exist in the DOM before you add the listener.

Try wrapping it like this:

document.addEventListener('DOMContentLoaded', () => {  const saveBar = document.getElementById('shopify-csb');  if (saveBar) {    saveBar.addEventListener('show', () => {      console.log('CSB showing');      // Disable your Cancel/Back buttons here    });        saveBar.addEventListener('hide', () => {      console.log('CSB hidden');      // Re-enable your Cancel/Back buttons here    });  }});

You can also use the showing getter to check the current state at any time:

const saveBar = document.getElementById('shopify-csb');if (saveBar.showing) {  // Save bar is currently visible}

The docs cover these instance methods here: https://shopify.dev/docs/api/app-bridge-library/web-components/ui-save-bar#ui-save-bar-instance

Let me know if that does the trick!

Thanks @Alan_G

Happy holidays!

It seems that we don’t have an issue getting the CSB to display, but either addEventListener doesn’t seem to be working, or the CSB isn’t configured correctly?

This is the code in the HTML.

<ui-save-bar id="shopify-csb">
  <button variant="primary"></button>
  <button></button>
</ui-save-bar>

For example, even if CSB is showing, saveBar.showing is returning false.

When we try the addEventListener code below.

document.addEventListener('DOMContentLoaded', () => {
    console.log('Running DOMContentLoaded');
    const saveBar = document.getElementById('shopify-csb');
    console.log('saveBar: '+saveBar);
    if (saveBar) {
        console.log('saveBar found');
        saveBar.addEventListener('show', () => {
            console.log('CSB showing');
            // Disable your Cancel/Back buttons here
        });
        saveBar.addEventListener('hide', () => {
            console.log('CSB hidden');
            // Re-enable your Cancel/Back buttons here
        });
    } else {
        console.log('no saveBar found');
    }
});

We get this output, but CSB showing or CSB hidden is being logged when the CSB is shown.

We then changed the code to this to ensure the Event Listener is actually attached, and confirmed it is.


document.addEventListener('DOMContentLoaded', () => {
    console.log('Running DOMContentLoaded');
    const saveBar = document.getElementById('shopify-csb');
    console.log('saveBar: '+saveBar);
    if (saveBar) {
        console.log('saveBar found');
        saveBar.addEventListener('show', csbShowingLog);
        saveBar.addEventListener('hide', () => {
            console.log('CSB hidden');
            // Re-enable your Cancel/Back buttons here
        });
    } else {
        console.log('no saveBar found');
    }
});

function csbShowingLog() {
    console.log('CSB showing');
}

Any ideas?

Hey @Ronald_G, happy holidays to you too!

This is definitely odd. One potential reason for why this may be happening here is that the show and hide events only fire when you use the Save Bar’s built-in methods to control it if you’re not doing that already. So, just having the <ui-save-bar> element in the DOM doesn’t mean App Bridge considers it “shown”, you’d need to explicitly call .show() to trigger that state change if that makes sense.

Somewhere in your app logic (like when a form field is modified), you’d call:

const saveBar = document.getElementById('shopify-csb');saveBar.show();

And when you want to hide it (like after saving):

saveBar.hide();

Once you’re using those methods, your event listeners should fire as expected, and the .showing property will correctly return true when the bar is visible.

Here’s a quick example of how you could set this up:

const saveBar = document.getElementById('shopify-csb');saveBar.addEventListener('show', () => {  console.log('CSB showing');  // Disable your Cancel/Back buttons here});saveBar.addEventListener('hide', () => {  console.log('CSB hidden');  // Re-enable your Cancel/Back buttons here});// Call this when the user makes a changesaveBar.show();

Let me know if that clears things up or if you’re still running into issues, happy to keep chatting on this.