Footer

The footer is meant to be the last visual element of every page. The social share functionality depends heavily on your project setup and therefore is not implemented here. The same holds for the search function, which is just a visual placeholder.


component variations

Default

This component is only meant to be used in a full page and won't render / behave correctly here. Please use the button below (Open on blank page) to see the component in action.
<footer class="o-footer">
  <div class="o-footer__search-container -secondary">
    <div class="e-container">
      <div class="o-footer__search">
        <div class="o-footer__search-cta">Still looking for something?</div>
        <form class="m-search-form" autocomplete="off">
          <div class="a-search-input">
            <input type="search" id="search-input-1" placeholder="Search" />
            <button
              type="submit"
              class="a-search-input__icon-search"
              aria-label="LoremIpsum"
            >
              <i class="a-icon ui-ic-search"></i>
            </button>
            <button type="button" class="a-search-input__icon-close">
              <i class="a-icon ui-ic-close-small"></i>
            </button>
          </div>
          <ul class="a-search-suggestions">
            <li class="a-search-suggestions__item">
              <a href="#" class="a-search-suggestions__result-link">
                <em>Product XYZ</em>
                Lorem ipsum dolor
              </a>
            </li>
            <li class="a-search-suggestions__item">
              <a href="#" class="a-search-suggestions__result-link">
                Lorem ipsum dolor sit amet, consetetur sadipscing elitr Product
                XYZ another line can be very long or very short, however when
                text breaks and the Product XYZ is mentioned again,
                <em>we should highlight this</em>
              </a>
            </li>
            <li class="a-search-suggestions__item">
              <a href="#" class="a-search-suggestions__result-link">
                Lorem ipsum
                <em>Product XYZ</em>
              </a>
            </li>
            <li class="a-search-suggestions__item">
              <a href="#" class="a-search-suggestions__result-link">
                <em>Product XYZ</em>
                Lorem ipsum dolor
              </a>
            </li>
            <li
              class="a-search-suggestions__item a-search-suggestions__results-link"
            >
              <div class="a-link -icon">
                <a href="/" target="_self">
                  <span>All</span>
                  <span>
                    Results
                    <i class="a-icon ui-ic-nosafe-lr-right-small"></i>
                  </span>
                </a>
              </div>
            </li>
          </ul>
        </form>
      </div>
    </div>
  </div>
  <div class="e-container">
    <div class="o-footer__top">
      <div class="o-footer__claim">Invented for life</div>
      <div class="m-language-selector">
        <div class="a-link -icon">
          <a href="https://www.bosch.com/websites-worldwide/" target="_blank">
            <i class="a-icon boschicon-bosch-ic-globe"></i>
            <span>Bosch Global</span>
          </a>
        </div>
        <div class="a-dropdown">
          <select
            id="demo"
            aria-label="here goes the aria label for the dropwdown"
          >
            <option value='"Deutsch"'>Deutsch</option>
            <option value='"English"'>English</option>
            <option value='"Französisch"'>Französisch</option>
          </select>
        </div>
      </div>
      <ul class="o-footer__links">
        <li>
          <div class="a-link a-link--integrated">
            <a href="#" target="_self"><span>Contact Us</span></a>
          </div>
        </li>
        <li>
          <div class="a-link a-link--integrated -icon">
            <a href="#" target="_self">
              <span>Product Security</span>
              <span>
                (PSIRT)
                <i class="a-icon ui-ic-nosafe-lr-externallink"></i>
              </span>
            </a>
          </div>
        </li>
        <li>
          <div class="a-link a-link--integrated">
            <a href="#" target="_self"><span>Licenses &amp; patents</span></a>
          </div>
        </li>
        <li>
          <div class="a-link a-link--integrated -icon">
            <a href="#" target="_self">
              <span>Purchasing &amp;</span>
              <span>
                logistics
                <i class="a-icon ui-ic-nosafe-lr-externallink"></i>
              </span>
            </a>
          </div>
        </li>
      </ul>
      <div class="o-footer__share">
        <button
          type="button"
          class="a-button a-button--integrated -without-label"
          aria-label="share button"
        >
          <i class="a-icon a-button__icon boschicon-bosch-ic-facebook"></i>
        </button>
        <button
          type="button"
          class="a-button a-button--integrated -without-label"
          aria-label="share button"
        >
          <i class="a-icon a-button__icon boschicon-bosch-ic-youtube"></i>
        </button>
        <button
          type="button"
          class="a-button a-button--integrated -without-label"
          aria-label="share button"
        >
          <i class="a-icon a-button__icon boschicon-bosch-ic-twitter-x"></i>
        </button>
        <button
          type="button"
          class="a-button a-button--integrated -without-label"
          aria-label="share button"
        >
          <i class="a-icon a-button__icon boschicon-bosch-ic-linkedin"></i>
        </button>
        <button
          type="button"
          class="a-button a-button--integrated -without-label"
          aria-label="share button"
        >
          <i class="a-icon a-button__icon boschicon-bosch-ic-xing"></i>
        </button>
        <button
          type="button"
          class="a-button a-button--integrated -without-label"
          aria-label="share button"
        >
          <i class="a-icon a-button__icon boschicon-bosch-ic-instagram"></i>
        </button>
      </div>
    </div>
    <hr class="a-divider" />
    <div class="o-footer__bottom">
      <ul class="o-footer__links">
        <li>
          <div class="a-link a-link--integrated">
            <a href="#" target="_self"><span>Corporate information</span></a>
          </div>
        </li>
        <li>
          <div class="a-link a-link--integrated">
            <a href="#" target="_self"><span>Legal notice</span></a>
          </div>
        </li>
        <li>
          <div class="a-link a-link--integrated">
            <a href="#" target="_self"><span>Data protection notice</span></a>
          </div>
        </li>
        <li>
          <div class="a-link a-link--integrated">
            <a href="#" target="_self"><span>Privacy settings</span></a>
          </div>
        </li>
      </ul>
      <div class="o-footer__copyright">
        © Robert Bosch Gmbh 2021, all rights reserved
      </div>
      <button
        type="button"
        class="a-button a-button--integrated -without-label o-footer__back-to-top"
        aria-label="button footer"
      >
        <i class="a-icon a-button__icon ui-ic-up"></i>
      </button>
    </div>
  </div>
</footer>

Minimal

This component is only meant to be used in a full page and won't render / behave correctly here. Please use the button below (Open on blank page) to see the component in action.
<footer class="o-footer -minimal">
  <hr class="a-divider" />
  <div class="e-container">
    <div class="o-footer__bottom">
      <ul class="o-footer__links">
        <li>
          <div class="a-link a-link--integrated">
            <a href="#" target="_self"><span>Imprint</span></a>
          </div>
        </li>
        <li>
          <div class="a-link a-link--integrated">
            <a href="#" target="_self"><span>Legal information</span></a>
          </div>
        </li>
        <li>
          <div class="a-link a-link--integrated">
            <a href="#" target="_self"><span>Data privacy</span></a>
          </div>
        </li>
        <li>
          <div class="a-link a-link--integrated">
            <a href="#" target="_self"><span>Disclosure documents</span></a>
          </div>
        </li>
      </ul>
      <hr class="a-divider" />
      <div class="o-footer__copyright">
        <i
          class="a-icon boschicon-bosch-ic-copyright-frame"
          title="Lorem Ipsum"
        ></i>
        2021 Bosch.IO GmbH, all rights reserved
      </div>
    </div>
  </div>
</footer>

additional content

demo

import ElementWithComponent from '../../ElementWithComponent';
import SearchForm from '../../molecules/searchForm';

const CLASS_SHOW_SUGGESTIONS = '-show-suggestions';

const suggestionsShown = (footer: Element): boolean => {
  return footer.classList.contains(CLASS_SHOW_SUGGESTIONS);
};

export default (): void => {
  // every button with the right class will show the "demo" modal on click
  // Exclude from selection the footers (those with class '-minimal') without an input inside
  const footers = Array.from(
    document.querySelectorAll('.o-footer:not(.-minimal)'),
  );

  footers.forEach((footer) => {
    let addSuggestionTimeout: ReturnType<typeof setTimeout> = null;

    const form: ElementWithComponent<SearchForm> =
      footer.querySelector('.m-search-form');

    form.component.searchInput.addEventListener('onInput', (value) => {
      /**
       * Show suggestions if:
       * - the input has at least 3 characters
       * and
       * - the suggestions are not already shown
       * and
       * - there is no timeout set to show the suggestions
       */
      if (
        value.length >= 3 &&
        !suggestionsShown(footer) &&
        addSuggestionTimeout === null
      ) {
        addSuggestionTimeout = setTimeout(() => {
          footer.classList.add(CLASS_SHOW_SUGGESTIONS);
          addSuggestionTimeout = null;
        }, 750);
      }

      /**
       * Hide suggestions if:
       * - the input has less than 3 characters
       * and
       * - the suggestions are currently visible
       */
      if (value.length < 3 && suggestionsShown(footer)) {
        addSuggestionTimeout = setTimeout(() => {
          footer.classList.remove(CLASS_SHOW_SUGGESTIONS);
          addSuggestionTimeout = null;
        }, 250);
      }
    });
  });
};

styles SCSS

.o-footer {
  &__search-container {
    padding-top: 2rem;
    padding-bottom: 2rem;

    .m-search-form {
      margin-bottom: 0;
    }
  }

  &__search-cta {
    @include size-l;

    font-weight: bold;
    margin-bottom: 1rem;
  }

  &__claim {
    @include size-xl;
  }

  &__top {
    padding-top: 3rem;
    padding-bottom: 1.5rem;
  }

  .m-language-selector,
  &__links,
  &__share {
    margin-top: 2rem;
  }

  &__share {
    margin-left: -0.75rem;
  }

  &__bottom {
    @include size-s;

    padding-top: 1.5rem;
    padding-bottom: 2rem;
    position: relative;
  }

  &__back-to-top {
    position: absolute;
    top: -0.25rem;
    right: -0.75rem;

    .a-icon {
      font-size: 2.25rem;
    }

    &:focus-visible {
      position: absolute;
    }
  }

  &__links {
    padding: 0;
    margin-bottom: 0;

    > li {
      font-size: inherit;
      padding: 0;

      /* stylelint-disable-next-line a11y/content-property-no-static-value */
      &::before {
        content: none;
      }
    }

    // again, we invent an "integrated link" here that can be replaced once the component exists
    a,
    a:visited {
      color: var(--integrated__enabled__front__default);

      &:hover {
        color: var(--integrated__enabled__front__hovered);
      }

      /* stylelint-disable-next-line no-descending-specificity */
      &:active {
        color: var(--integrated__enabled__front__pressed);
      }
    }

    /* stylelint-disable-next-line no-descending-specificity */
    .-external a {
      // we do _not_ want the underline below the external link icon, so
      // see https://stackoverflow.com/questions/1238881/text-decoration-and-the-after-pseudo-element-revisited,
      // and in particular the answer
      // https://stackoverflow.com/a/15688237
      display: inline-block;

      /* stylelint-disable-next-line a11y/content-property-no-static-value */
      &::after {
        /* stylelint-disable-next-line font-family-no-missing-generic-family-keyword */

        @include uiIconForComponents();

        content: var(--ui-ic-inline-externallink);
        display: inline-block;

        // nudge the icon into position
        padding-left: 0.5em;
      }

      /* stylelint-disable-next-line selector-max-compound-selectors */
      &:hover a::after {
        text-decoration: none;
      }
    }
  }

  &__bottom &__links {
    margin-bottom: 1rem;
    margin-top: 0;
  }

  .m-search-form {
    position: relative;

    .a-search-input {
      z-index: 2;
    }
  }

  .a-search-suggestions {
    max-height: 0;
    background: var(--bosch-white);
    overflow: hidden;
    position: absolute;
    margin-top: -3rem;
    z-index: 1;
  }

  &:not(.-show-suggestions) .a-search-suggestions__item {
    visibility: hidden;
  }

  &.-show-suggestions .a-search-suggestions {
    max-height: 100vh;
    margin-top: 0;
    transition: max-height $default-transition-easing $default-transition-timing;
    box-shadow: 0 0 1rem rgb(0 0 0 / 25%);
  }

  // Styling for the footer's minimal variant.
  &.-minimal {
    > .a-divider {
      margin: 0;
    }

    .o-footer__bottom {
      display: flex;
      flex-direction: column;
      padding: 1rem 0;

      .a-divider {
        margin: 1rem 0;
        order: 2;
      }
    }

    .o-footer__copyright {
      align-items: center;
      display: flex;
      order: 1;

      .a-icon {
        font-size: 1.125rem;
        margin-right: 0.25rem;
      }
    }

    .o-footer__links {
      margin-bottom: 0;
      order: 3;

      li {
        margin-bottom: 1.5rem;
      }

      li:last-child {
        margin-bottom: 0;
      }
    }
  }
}

@include tablet-and-up {
  .o-footer {
    &__search {
      align-items: baseline;
      display: flex;

      .m-search-form {
        flex: 1;
        margin-left: 2rem;
      }
    }

    &__search-cta {
      flex: 1;
      margin-bottom: 0;
    }

    &__top {
      display: flex;
      flex-direction: row;
      flex-wrap: wrap;
      justify-content: space-between;
      padding-top: 3.5rem;
      padding-bottom: 3.5rem;
    }

    &__claim {
      margin-top: 0.5rem;
      // take ~2/3 of the available space, we need to take into account up to 6 icons
      width: 60%;
    }

    &__share {
      justify-self: right;
      margin-top: 0;
      order: 1;
      position: relative;
      right: -0.75rem;
    }

    &__bottom {
      display: flex;
      flex-wrap: wrap-reverse;
    }

    &__copyright {
      margin-right: 1.5rem;
      order: 1;
    }

    .m-language-selector {
      order: 2;
      width: 100%;
    }

    &__links {
      order: 3;
    }

    &__top &__links,
    &__bottom &__links {
      display: flex;
      flex-wrap: wrap;
      align-items: center;

      > li {
        display: inline-block;
        margin-bottom: 0;

        &:not(:last-child) {
          margin-right: 1.5rem;
        }
      }
    }

    &__bottom &__links {
      // do no slide "under " the back-to-top arrow
      padding-right: 3rem;
    }

    &.-minimal {
      .o-footer__copyright {
        margin-right: 0;
      }

      .o-footer__links {
        padding-right: 0;

        li {
          margin-right: 2rem;
          margin-bottom: 0;
        }

        li:last-child {
          margin-right: 0;
        }
      }
    }
  }
}

@include desktop-and-up {
  .o-footer {
    .m-language-selector {
      width: unset;
    }
    &__search-cta {
      @include size-xl;
    }

    &__top &__links {
      align-self: start;
      justify-self: end;
      margin-top: 1.9375rem; // baseline-align with the language selector
    }

    &.-minimal {
      .o-footer__bottom {
        flex-direction: row;
        justify-content: space-between;
        padding: 0.5rem 0;

        /* stylelint-disable-next-line a11y/no-display-none */
        .a-divider {
          display: none;
        }
      }
    }
  }
}