Versions of Components

I am using a component for my navigation so that it is the same nav across all of my pages, but I want to create a variation based on whether or not the page starts with a hero image.

  • If page has hero image, navigation should have no background and nav items should be white.

  • If page has NO hero image, image should have a background.

~ Bonus would be change Variation 1 to variation 2 on scroll with a fixed nav.

I can’t figure out how to make variations without changing the component across the board. (I’m not wanting to make content changes, which Properties allow)


Here is my site Read-Only: [LINK]1
(how to share your site Read-Only link)

You could use component slots to do something like this. Make the component, open the component to edit, then add a slot to it (treat it like a normal Div for styling purposes). Then close the editing and drag another component into the slot.

Alternately, you could also just add an image to the component, make it absolute with Z of zero (make sure the nested item above it is Relative with a Z of 1 or higher). Then add a conditional visibility to just the image. There are rarely only a single way of doing things.

Thanks for the response. I hadn’t heard of slots, thanks for turning me onto them - still trying to wrap my head around them. Seems like a cumbersome solution.

I’m not sure you’re understanding my use case. I have only seen the slots applied to cards and card sections, not navbars. I want to have a navbar that functions the same across all pages but has slightly different styling depending on whether or not there is a hero image (the image is not on the navbar but on the page). If I make a change to to the navigation, I want that reflected across all pages.

Or I’m completely misunderstanding your suggestion, but it sound like you’re telling me to put an image in the navbar.

You can achieve this with javascript.
I would build a component that is a absolute container containing a image. It would receive a custom attribute that would be searched on the javascript, adding or no the background color.
Also possible to apply the background color when scrolling the page with the fixed javascrip.
I will try to make this by tomorrow and send you the code.

1 Like

I use images instead of backgrounds most of the time. Backgrounds don’t have alt text and are ignored by screen readers. While that is useful at times, usually I need the text visible for screen readers.

Here is the code:

<script>
  // Use window.Webflow to ensure the page is fully loaded before running the script
  window.Webflow = window.Webflow || [];
  window.Webflow.push(() => {
    const navbar = document.querySelector(".navbar");
    const navBg = document.querySelector(".nav__bg");
    const heroImage = document.querySelector("[data-hero-image]");

    const INITIAL_BG_OPACITY = '0';
    const BG_OPACITY_WHEN_PAGE_SCROLLED = '1';

    function throttle(func, wait) {
      let timeout;
      return function () {
        const context = this;
        const args = arguments;
        if (!timeout) {
          func.apply(context, args);
          timeout = setTimeout(() => {
            timeout = null;
          }, wait);
        }
      };
    }

    function debounce(func, wait) {
      let timeout;
      return function () {
        const context = this;
        const args = arguments;
        clearTimeout(timeout);
        timeout = setTimeout(() => {
          timeout = null;
          func.apply(context, args);
        }, wait);
      };
    }

    // Set initial opacity based on the presence of the hero image
    if (heroImage && navBg) {
      navBg.style.opacity = "0";
      navbar.setAttribute("data-page-has-hero-image", "true");
    } else if (!heroImage && navBg && navbar) {
      navBg.style.setProperty("opacity", INITIAL_BG_OPACITY, "important");
      navbar.setAttribute("data-page-has-hero-image", "false");
    }

    // Handle scroll event
    const handleScroll = () => {
      if (!navBg) return;

      if (window.pageYOffset > 0) {
        navBg.style.opacity = BG_OPACITY_WHEN_PAGE_SCROLLED;
      } else {
        navBg.style.opacity = INITIAL_BG_OPACITY;
      }
    };

    const debouncedHandleScroll = debounce(handleScroll, 100);
    const throttledHandleScroll = throttle(handleScroll, 100);

    window.addEventListener('scroll', debouncedHandleScroll);
    window.addEventListener('scroll', throttledHandleScroll);

    // Initial call to set the correct opacity on page load
    handleScroll();
  });
</script>

I haven’t tested it, so if it runs any error let me know.

Add embed for script, add a class to hide it and add the code above.

Add embed for style, add a class to hide it and add the code bellow.

<style>
	.navbar[data-page-has-hero-image='true'] .MainMenuLink {
  	color: white;
  }
</style>

  • Create a component for the “background” image.
    Don’t forget to add the custom attribute to it: data-hero-image
    It will use a container with absolute position with 0 in all directions and z-index -1. Add a image to it and set it’s component override to be able to change the image for different pages.
    Add this component directly inside the Hero Section and add a style overflow hidden to the Hero Section.

  • Move the color overlay to the MainHero component and remove it from the HeroSection

  • Add position fixed for the navbar container and add the custom attribute: data-page-has-hero-image = false

I think this is it.
For the pages that there is a heroImage from the component, the navbar will be initially transparent. When scrolling down it should be white and if go to the top should be transparent again.

This was done quickly and without testing, but I hope it’s useful.

Good luck.

There are three general techniques you can use.

OPTION 1 - Multi-modal approach;
Inside of your component, make a full duplicate of your nav contents. One for each of your use cases. Then link those to visibility properties. In your instances, you can then switch on and off those “variants”. Single component, single set of properties, and relatively easy to manage. I use this approach sometimes for darkmode lightmode settings.

OPTION 2 - Switchable CSS
Inside of your component, you can place an Embed and custom <style> CSS. Often I’ll design a component as light mode, then the Embed will contain darkmode override styling. Remove the background, change font colors. etc. That entire Embed can then be connected to a visibility property so that you can switch it on or off easily. Main thing is this requires comfort with CSS.

OPTION 3 - Outer-inner slotted component approach;
Use the new component slots feature. The outer component would dictate container things like the background, and the default foreground color. You’d have two versions of this outer component, or just one with the multi-modal approach mentioned in option 1 above.
The inner slotted component would just be your nav. If it is set to inherit text color, it will pick up the container’s CSS rules automatically. Otherwise you could govern that in various ways, like a linked property to the parent.

Technically option3 requires different components on different pages, but the “meat” of the nav is in one single component that is used sitewide, so e.g. nav changes won’t require editing multiple components later.

1 Like