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.
table of content
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="button" class="a-search-input__icon-close">
<i class="a-icon ui-ic-close-small"></i>
</button>
<button
type="submit"
class="a-search-input__icon-search"
aria-label="Search"
>
<i class="a-icon ui-ic-search"></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 & patents</span></a>
</div>
</li>
<li>
<div class="a-link a-link--integrated -icon">
<a href="#" target="_self">
<span>Purchasing &</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;
}
}
}
}
}