Banners
Banners are components that deliver main image and content in various configurations.
Responsive Display
Display blocks that switch between horizontal/vertical arrangement based on parent container's size.
import { SfButton } from '@storefront-ui/react';
import classNames from 'classnames';
const displayDetails = [
{
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/display-2.png',
title: 'Pack it Up',
subtitle: 'Be active',
description: 'Explore the great outdoors with our backpacks',
buttonText: 'Discover now',
reverse: true,
backgroundColor: 'bg-warning-200',
},
{
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/display.png',
title: 'Sunny Days Ahead',
subtitle: 'Be inspired',
description: 'Step out in style with our sunglasses collection',
buttonText: 'Discover now',
reverse: true,
backgroundColor: 'bg-negative-200',
},
];
export default function DisplayHorizontalBlock() {
return (
<div className="grid md:flex md:flex-row flex-wrap gap-6 max-w-[1540px]">
{displayDetails.map(({ image, title, subtitle, description, buttonText, backgroundColor, reverse }) => (
<div
key={title}
className={classNames(
'relative flex md:max-w-[1536px] md:[&:not(:first-of-type)]:flex-1 md:first-of-type:w-full @container group',
backgroundColor,
)}
>
<a
className="absolute w-full h-full z-1 focus-visible:outline focus-visible:rounded-lg"
aria-label={title}
href="#"
/>
<div
className={classNames('flex justify-between overflow-hidden grow flex-col @md:flex-row', {
'@md:flex-row-reverse flex-col-reverse': reverse,
})}
>
<div className="grow flex flex-col justify-center items-start p-4 @sm:p-6 @3xl:p-10 max-w-1/2 items-center text-center @md:items-start @md:text-start">
<p className="uppercase typography-text-xs block font-medium tracking-widest @3xl:typography-headline-6">
{subtitle}
</p>
<h2 className="mb-4 mt-2 font-semibold typography-display-3 -tracking-wide @3xl:typography-display-1">
{title}
</h2>
<p className="typography-text-base block mb-4 @3xl:typography-text-lg">{description}</p>
<SfButton
blank
className="text-white bg-neutral-700 hover:bg-neutral-800 active:bg-neutral-900 group-hover:bg-neutral-800 group-active:bg-neutral-900 group-has-[:focus-visible]:outline group-has-[:focus-visible]:outline-offset pointer-events-none"
tabIndex={-1}
>
{buttonText}
</SfButton>
</div>
<div className="flex shrink-0 items-center w-full @md:w-1/2 @md:self-start @md:object-contain">
<img src={image} alt={title} className="w-full" />
</div>
</div>
</div>
))}
</div>
);
}
Horizontal Display
Horizontal display block with image and content to the side.
import { SfButton } from '@storefront-ui/react';
import classNames from 'classnames';
const displayDetails = [
{
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/display.png',
title: 'Sunny Days Ahead',
subtitle: 'Be inspired',
description: 'Step out in style with our sunglasses collection',
buttonText: 'Discover now',
reverse: false,
backgroundColor: 'bg-negative-200',
},
{
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/display-2.png',
title: 'Pack it Up',
subtitle: 'Be active',
description: 'Explore the great outdoors with our backpacks',
buttonText: 'Discover now',
reverse: true,
backgroundColor: 'bg-warning-200',
},
{
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/display-3.png',
title: 'Fresh and Bold',
subtitle: 'New collection',
description: 'Add a pop up color to your outfit',
buttonText: 'Discover now',
reverse: false,
backgroundColor: 'bg-secondary-200',
},
];
export default function DisplayHorizontalBlock() {
return (
<div className="grid md:flex md:flex-row flex-wrap gap-6 max-w-[1540px]">
{displayDetails.map(({ image, title, subtitle, description, buttonText, backgroundColor, reverse }) => (
<div
key={title}
className={classNames(
'relative flex md:max-w-[1536px] md:[&:not(:first-of-type)]:flex-1 md:first-of-type:w-full @container group',
backgroundColor,
)}
>
<a
className="absolute w-full h-full z-1 focus-visible:outline focus-visible:rounded-lg"
aria-label={title}
href="#"
/>
<div
className={classNames('flex justify-between overflow-hidden grow', {
'flex-row-reverse': reverse,
})}
>
<div className="grow flex flex-col justify-center items-start p-4 @sm:p-6 @3xl:p-10 max-w-1/2">
<p className="uppercase typography-text-xs block font-medium tracking-widest @3xl:typography-headline-6">
{subtitle}
</p>
<h2 className="mb-4 mt-2 font-semibold typography-display-3 -tracking-wide @3xl:typography-display-1">
{title}
</h2>
<p className="typography-text-base block mb-4 @3xl:typography-text-lg">{description}</p>
<SfButton
blank
className="text-white bg-neutral-700 hover:bg-neutral-800 active:bg-neutral-900 group-hover:bg-neutral-800 group-active:bg-neutral-900 group-has-[:focus-visible]:outline group-has-[:focus-visible]:outline-offset pointer-events-none"
tabIndex={-1}
>
{buttonText}
</SfButton>
</div>
<div className="shrink-0 w-1/2 self-start object-contain">
<img src={image} alt={title} className="w-full" />
</div>
</div>
</div>
))}
</div>
);
}
Vertical Display
Vertical display block with image and content below or above it.
import { SfButton } from '@storefront-ui/react';
import classNames from 'classnames';
const displayDetails = [
{
title: 'Pack it Up',
subtitle: 'Be active',
description: 'Explore the great outdoors with our backpacks',
callToAction: 'Discover now',
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/display-2.png',
backgroundColor: 'bg-warning-200',
reverse: false,
},
{
title: 'Sunny Days Ahead',
subtitle: 'Be inspired',
description: 'Step out in style with our sunglasses collection',
callToAction: 'Discover now',
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/display.png',
backgroundColor: 'bg-negative-200',
reverse: true,
},
];
export default function DisplayVertical() {
return (
<div className="flex flex-col gap-6 md:flex-row">
{displayDetails.map(({ title, subtitle, description, callToAction, image, backgroundColor, reverse }) => (
<div
key={title}
className={classNames(
`relative flex flex-col justify-between rounded-md md:items-center md:basis-1/2 ${backgroundColor} @container group`,
{ 'flex-col-reverse': reverse },
)}
>
<a
className="absolute w-full h-full z-1 focus-visible:outline focus-visible:rounded-lg"
aria-label={title}
href="#"
/>
<div className="flex flex-col items-center p-4 @sm:p-6 text-center @3xl:p-10">
<p className="uppercase typography-text-xs block font-medium tracking-widest @3xl:typography-headline-6">
{subtitle}
</p>
<h2 className="mb-4 mt-2 font-semibold typography-display-3 -tracking-wide @3xl:typography-display-1">
{title}
</h2>
<p className="typography-text-base block mb-4 @3xl:typography-text-lg">{description}</p>
<SfButton
blank
className="text-white bg-neutral-700 hover:bg-neutral-800 active:bg-neutral-900 group-hover:bg-neutral-800 group-active:bg-neutral-900 group-has-[:focus-visible]:outline group-has-[:focus-visible]:outline-offset pointer-events-none"
tabIndex={-1}
>
{callToAction}
</SfButton>
</div>
<div className="flex items-center w-full">
<img src={image} alt={title} className="w-full" />
</div>
</div>
))}
</div>
);
}
Multiple vertical Displays
Four vertical displays in row on desktop.
import { SfButton } from '@storefront-ui/react';
import classNames from 'classnames';
const displayDetails = [
{
title: 'Pack it Up',
subtitle: 'Be active',
description: 'Explore the great outdoors with our backpacks',
callToAction: 'Discover now',
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/display-2.png',
backgroundColor: 'bg-warning-200',
reverse: false,
},
{
title: 'Sunny Days Ahead',
subtitle: 'Be inspired',
description: 'Step out in style with our sunglasses collection',
callToAction: 'Discover now',
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/display.png',
backgroundColor: 'bg-negative-200',
reverse: true,
},
{
title: 'Fresh and Bold',
subtitle: 'New collection',
description: 'Add a pop up color to your outfit',
callToAction: 'Discover now',
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/display-3.png',
backgroundColor: 'bg-secondary-200',
reverse: false,
},
];
export default function DisplayVerticalMultiple() {
return (
<div className="flex flex-col gap-6 md:flex-row">
<div className="flex flex-col grow gap-6 md:flex-row">
{displayDetails.map(
({ title, subtitle, description, callToAction, image, backgroundColor, reverse }, index) => (
<div
key={`${title}-${index}`}
className={classNames(
`relative flex flex-col justify-between rounded-md md:items-center md:basis-1/2 ${backgroundColor} @container group`,
{ 'flex-col-reverse': reverse },
)}
>
<a
className="absolute w-full h-full z-1 focus-visible:outline focus-visible:rounded-lg"
aria-label={title}
href="#"
/>
<div className="flex flex-col p-4 @sm:p-6 text-center items-center @3xl:p-10">
<p className="uppercase typography-text-xs block font-medium tracking-widest @3xl:typography-headline-6">
{subtitle}
</p>
<h2 className="mb-4 mt-2 font-semibold typography-display-3 -tracking-wide @3xl:typography-display-1">
{title}
</h2>
<p className="typography-text-base block mb-4 @3xl:typography-text-lg">{description}</p>
<SfButton
blank
className="text-white bg-neutral-700 hover:bg-neutral-800 active:bg-neutral-900 group-hover:bg-neutral-800 group-active:bg-neutral-900 group-has-[:focus-visible]:outline group-has-[:focus-visible]:outline-offset pointer-events-none"
tabIndex={-1}
>
{callToAction}
</SfButton>
</div>
<div className="flex items-center w-full">
<img src={image} alt={title} className="w-full" />
</div>
</div>
),
)}
</div>
</div>
);
}
Display With Image Overlay
Display block with image filling all of its background area.
import { SfButton } from '@storefront-ui/react';
const displayDetails = [
{
title: 'Cap Game Strong',
subtitle: 'Special Offer',
description: 'Score serious style points with our Open Capsule collection',
buttonText: 'Browse offers',
backgroundImage: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/display-overlay.png',
},
];
export default function DisplayWithImageOverlay() {
return (
<div className="max-w-[1540px]">
{displayDetails.map(({ title, subtitle, description, buttonText, backgroundImage }) => (
<div key={title} className="relative flex text-white max-w-[1536px] @container group">
<a
className="absolute w-full h-full z-1 focus-visible:outline focus-visible:rounded-lg"
aria-label={title}
href="#"
/>
<div className="h-[680px] @3xl:h-auto @3xl:aspect-[2] flex justify-center overflow-hidden grow">
<div className="grow flex flex-col justify-center items-center text-center p-4 @sm:p-6 @3xl:p-10 max-w-1/2">
<p className="uppercase typography-text-xs block font-medium tracking-widest @3xl:typography-headline-6">
{subtitle}
</p>
<h2 className="mb-4 mt-2 font-semibold typography-display-3 -tracking-wide @3xl:typography-display-1">
{title}
</h2>
<p className="typography-text-base block mb-4 @3xl:typography-text-lg">{description}</p>
<SfButton
blank
className="w-[200px] bg-white text-primary-700 ring-secondary-400 group-hover:bg-primary-100 group-hover:hover:text-primary-800 group-hover:ring-secondary-500 group-active:bg-primary-200 group-active:text-primary-900 group-active:ring-secondary-600 group-has-[:focus-visible]:outline group-has-[:focus-visible]:outline-offset pointer-events-none"
tabIndex={-1}
variant="secondary"
>
{buttonText}
</SfButton>
</div>
<div className="absolute inset-0 z-[-1] overflow-hidden bg-primary-900">
<img src={backgroundImage} alt={title} className="w-full h-full object-cover opacity-75" />
</div>
</div>
</div>
))}
</div>
);
}
Hero
The Hero block simplifies the process of creating stunning hero sections for your website. With Hero, you have the flexibility to seamlessly integrate a main image and customize your content to suit your needs. Additionally, Hero allows adding background images tailored for both mobile and desktop devices. To ensure an optimal blend of performance and visual appeal, we recommend adhering to the following image guidelines:
Desktop Background Images: Aspect ratio: 2:1 Example size: 2160 x 1080px
Mobile Background Images: Aspect ratio: 2:5 Example size: 420 x 1050px
import classNames from 'classnames';
import { SfButton } from '@storefront-ui/react';
const heroDetails = {
headline: 'New collection',
title: 'Made to move. Built to win.',
description: 'The new sport collection is now in store.',
callToAction: 'Order now',
callToActionSecondary: 'Show more',
backgroundImage: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/hero-bg-2.png',
backgroundImageMobile: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/hero-bg-mobile-2.png',
image: undefined,
imageAlt: undefined,
variant: 'dark',
};
export default function Hero() {
const {
title,
headline,
description,
callToAction,
callToActionSecondary,
backgroundImage,
backgroundImageMobile,
image,
imageAlt,
variant,
} = heroDetails;
return (
<div className="relative h-dvh w-dvw shrink-0">
<picture>
<source srcSet={backgroundImage} media="(min-width: 768px)" />
<img src={backgroundImageMobile} className="absolute w-full h-full z-[-1] object-cover" alt="hero" />
</picture>
<div
className={classNames(
'h-full w-full max-w-[1536px] mx-auto flex flex-col justify-end md:justify-center',
variant === 'dark' ? 'text-white' : 'text-neutral-900',
)}
>
<div className="p-4 md:p-10 flex flex-col">
<p className="typography-text-xs md:typography-text-sm font-bold tracking-widest uppercase">{headline}</p>
<h1 className="mt-2 mb-4 typography-display-2 md:typography-display-1 md:leading-[67.5px] font-bold">
{title}
</h1>
<p className="typography-text-base md:typography-text-lg">{description}</p>
<div className="mt-6 flex flex-col md:flex-row gap-4">
<SfButton size="lg" className="bg-white" variant="secondary">
{callToAction}
</SfButton>
<SfButton size="lg">{callToActionSecondary}</SfButton>
</div>
</div>
</div>
</div>
);
}
Hero With Side Image
Enhance your Hero section with a contextual image on the side.
import classNames from 'classnames';
import { SfButton } from '@storefront-ui/react';
const heroDetails = {
headline: 'Feel the music',
title: 'New Wireless Pro',
description: 'Spatial audio. Adjustable ear cups. On-device controls. All-day battery.',
callToAction: 'Order now',
callToActionSecondary: 'Show more',
backgroundImage: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/hero-bg.png',
backgroundImageMobile: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/hero-bg-mobile.png',
image: 'https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/hero-headphones.png',
imageAlt: 'Headphones',
variant: 'light',
};
export default function Hero() {
const {
title,
headline,
description,
callToAction,
callToActionSecondary,
backgroundImage,
backgroundImageMobile,
image,
imageAlt,
variant,
} = heroDetails;
return (
<div className="relative h-dvh w-dvh shrink-0">
<picture>
<source srcSet={backgroundImage} media="(min-width: 768px)" />
<img src={backgroundImageMobile} className="absolute w-full h-full z-[-1] object-cover" />
</picture>
<div
className={classNames(
'h-full w-full max-w-[1536px] mx-auto flex flex-col md:flex-row-reverse md:justify-center',
variant === 'dark' ? 'text-white' : 'text-neutral-900',
)}
>
<div className="flex flex-col md:basis-2/4 md:items-stretch">
<img src={image} alt={imageAlt} className="h-full object-cover object-left overflow-visible" />
</div>
<div className="p-4 md:p-10 flex flex-col justify-center basis-2/4 md:items-start">
<p className="typography-text-xs md:typography-text-sm font-bold tracking-widest uppercase">{headline}</p>
<h1 className="mt-2 mb-4 typography-display-2 md:typography-display-1 md:leading-[67.5px] font-bold">
{title}
</h1>
<p className="typography-text-base md:typography-text-lg">{description}</p>
<div className="mt-6 flex flex-col md:flex-row gap-4">
<SfButton size="lg">{callToAction}</SfButton>
<SfButton size="lg" className="bg-white" variant="secondary">
{callToActionSecondary}
</SfButton>
</div>
</div>
</div>
</div>
);
}