NavbarTop
The NavbarTop block is used as navigation. Usually it's at the top of a page and has elements like company logo, links to main categories or a menu button, search input and action buttons that can open a cart, wishlist or login modal.
NavbarTop with white background
import { useState } from 'react';
import {
SfButton,
SfIconShoppingCart,
SfIconFavorite,
SfIconPerson,
SfIconExpandMore,
SfInput,
SfIconSearch,
SfIconMenu,
} from '@storefront-ui/react';
export default function TopNav() {
const [inputValue, setInputValue] = useState('');
const actionItems = [
{
icon: <SfIconShoppingCart />,
label: '',
ariaLabel: 'Cart',
role: 'button',
},
{
icon: <SfIconFavorite />,
label: '',
ariaLabel: 'Wishlist',
role: 'button',
},
{
label: 'Log in',
icon: <SfIconPerson />,
ariaLabel: 'Log in',
role: 'login',
},
];
const search = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
alert(`Successfully found 10 results for ${inputValue}`);
};
return (
<header className="flex justify-center w-full py-2 px-4 lg:py-5 lg:px-6 bg-white border-b border-neutral-200">
<div className="flex flex-wrap lg:flex-nowrap items-center flex-row justify-start h-full max-w-[1536px] w-full">
<a
href="#"
aria-label="SF Homepage"
className="inline-block mr-4 focus-visible:outline focus-visible:outline-offset focus-visible:rounded-sm shrink-0"
>
<picture>
<source srcSet="https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/vsf_logo.svg" media="(min-width: 768px)" />
<img
src="https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/vsf_logo_sign.svg"
alt="Sf Logo"
className="w-8 h-8 md:h-6 md:w-[176px] lg:w-[12.5rem] lg:h-[1.75rem]"
/>
</picture>
</a>
<SfButton
aria-label="Open categories"
className="lg:hidden order-first lg:order-1 mr-4"
square
variant="tertiary"
>
<SfIconMenu />
</SfButton>
<SfButton
className="hidden lg:flex lg:mr-4"
variant="tertiary"
slotSuffix={<SfIconExpandMore className="hidden lg:block" />}
>
<span className="hidden lg:flex whitespace-nowrap">Browse products</span>
</SfButton>
<form
role="search"
className="flex flex-[100%] order-last lg:order-3 mt-2 lg:mt-0 pb-2 lg:pb-0"
onSubmit={search}
>
<SfInput
value={inputValue}
type="search"
className="[&::-webkit-search-cancel-button]:appearance-none"
placeholder="Search"
wrapperClassName="flex-1 h-10 pr-0"
size="base"
slotSuffix={
<span className="flex items-center">
<SfButton
variant="tertiary"
square
aria-label="search"
type="submit"
className="rounded-l-none hover:bg-transparent active:bg-transparent"
>
<SfIconSearch />
</SfButton>
</span>
}
onChange={(event) => setInputValue(event.target.value)}
/>
</form>
<nav className="flex-1 flex justify-end lg:order-last lg:ml-4">
<div className="flex flex-row flex-nowrap">
{actionItems.map((actionItem) => (
<SfButton
key={actionItem.ariaLabel}
className="mr-2 -ml-0.5 rounded-md text-primary-700 hover:bg-primary-100 active:bg-primary-200 hover:text-primary-600 active:text-primary-700"
aria-label={actionItem.ariaLabel}
variant="tertiary"
square
slotPrefix={actionItem.icon}
>
{actionItem.role === 'login' && (
<p className="hidden xl:inline-flex whitespace-nowrap">{actionItem.label}</p>
)}
</SfButton>
))}
</div>
</nav>
</div>
</header>
);
}
NavbarTop with filled background
import { useState } from 'react';
import {
SfButton,
SfIconShoppingCart,
SfIconFavorite,
SfIconPerson,
SfIconExpandMore,
SfInput,
SfIconSearch,
SfIconMenu,
} from '@storefront-ui/react';
export default function TopNavFilled() {
const [inputValue, setInputValue] = useState('');
const actionItems = [
{
icon: <SfIconShoppingCart />,
label: '',
ariaLabel: 'Cart',
role: 'button',
},
{
icon: <SfIconFavorite />,
label: '',
ariaLabel: 'Wishlist',
role: 'button',
},
{
label: 'Log in',
icon: <SfIconPerson />,
ariaLabel: 'Log in',
role: 'login',
},
];
const search = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
alert(`Successfully found 10 results for ${inputValue}`);
};
return (
<header className="flex justify-center w-full py-2 px-4 lg:py-5 lg:px-6 text-white border-0 bg-primary-700">
<div className="flex flex-wrap lg:flex-nowrap items-center flex-row justify-start h-full max-w-[1536px] w-full">
<a
href="#"
aria-label="SF Homepage"
className="inline-block mr-4 focus-visible:outline focus-visible:outline-offset focus-visible:rounded-sm shrink-0"
>
<picture>
<source srcSet="https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/vsf_logo_white.svg" media="(min-width: 768px)" />
<img
src="https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/vsf_logo_sign_white.svg"
alt="Sf Logo"
className="w-8 h-8 md:h-6 md:w-[176px] lg:w-[12.5rem] lg:h-[1.75rem]"
/>
</picture>
</a>
<SfButton
aria-label="Open categories"
className="lg:hidden order-first lg:order-1 mr-4 text-white hover:text-white active:text-white hover:bg-primary-800 active:bg-primary-900"
square
variant="tertiary"
>
<SfIconMenu />
</SfButton>
<SfButton
className="hidden lg:flex lg:mr-4 text-white hover:text-white active:text-white hover:bg-primary-800 active:bg-primary-900"
type="button"
variant="tertiary"
slotSuffix={<SfIconExpandMore className="hidden lg:block" />}
>
<span className="hidden lg:flex whitespace-nowrap">Browse products</span>
</SfButton>
<form
role="search"
className="flex flex-[100%] order-last lg:order-3 mt-2 lg:mt-0 pb-2 lg:pb-0"
onSubmit={search}
>
<SfInput
value={inputValue}
type="search"
className="[&::-webkit-search-cancel-button]:appearance-none"
placeholder="Search"
wrapperClassName="flex-1 h-10 pr-0"
size="base"
slotSuffix={
<span className="flex items-center">
<SfButton
variant="tertiary"
square
aria-label="search"
type="submit"
className="rounded-l-none hover:bg-transparent active:bg-transparent"
>
<SfIconSearch />
</SfButton>
</span>
}
onChange={(event) => setInputValue(event.target.value)}
/>
</form>
<nav className="flex-1 flex justify-end lg:order-last lg:ml-4">
<div className="flex flex-row flex-nowrap">
{actionItems.map((actionItem) => (
<SfButton
key={actionItem.ariaLabel}
className="mr-2 -ml-0.5 rounded-md text-white hover:text-white active:text-white hover:bg-primary-800 active:bg-primary-900"
aria-label={actionItem.ariaLabel}
variant="tertiary"
square
slotPrefix={actionItem.icon}
>
{actionItem.role === 'login' && (
<p className="hidden xl:inline-flex whitespace-nowrap">{actionItem.label}</p>
)}
</SfButton>
))}
</div>
</nav>
</div>
</header>
);
}
NavbarTop with white background and simple mobile bar
The alternate NavbarTop variant designed to work seamlessly with the NavbarBottom, providing a cohesive mobile navigation experience.
By combining with the NavbarBottom, you can create a unified navigation structure that accommodates both top and bottom navigation elements on mobile devices. This ensures a smooth and intuitive user experience, allowing users to access important navigation options easily.
import { useState } from 'react';
import {
SfButton,
SfIconShoppingCart,
SfIconFavorite,
SfIconPerson,
SfIconExpandMore,
SfInput,
SfIconSearch,
SfIconMenu,
SfIconArrowBack,
} from '@storefront-ui/react';
export default function TopNavSimpleMobile() {
const [inputValue, setInputValue] = useState('');
const actionItems = [
{
icon: <SfIconShoppingCart />,
label: '',
ariaLabel: 'Cart',
role: 'button',
},
{
icon: <SfIconFavorite />,
label: '',
ariaLabel: 'Wishlist',
role: 'button',
},
{
label: 'Log in',
icon: <SfIconPerson />,
ariaLabel: 'Log in',
role: 'login',
},
];
const search = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
alert(`Successfully found 10 results for ${inputValue}`);
};
return (
<header className="flex justify-center w-full py-2 px-4 lg:py-5 lg:px-6 bg-white border-b border-neutral-200">
<div className="flex flex-wrap justify-between lg:flex-nowrap items-center flex-row md:justify-start h-full max-w-[1536px] w-full">
<SfButton variant="tertiary" square className="md:hidden" aria-label="Go back">
<SfIconArrowBack />
</SfButton>
<a
href="#"
aria-label="SF Homepage"
className="inline-block mr-4 focus-visible:outline focus-visible:outline-offset focus-visible:rounded-sm shrink-0"
>
<img
src="https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/vsf_logo.svg"
alt="Sf Logo"
className="w-[175px] md:h-6 md:w-[176px] lg:w-[12.5rem] lg:h-[1.75rem]"
/>
</a>
<SfButton variant="tertiary" square className="md:hidden" aria-label="Search">
<SfIconSearch />
</SfButton>
<SfButton
aria-label="Open categories"
className="hidden md:block lg:hidden order-first lg:order-1 mr-4"
square
variant="tertiary"
>
<SfIconMenu />
</SfButton>
<SfButton
className="hidden lg:flex lg:mr-4"
type="button"
variant="tertiary"
slotSuffix={<SfIconExpandMore className="hidden lg:block" />}
>
<span className="hidden lg:flex whitespace-nowrap">Browse products</span>
</SfButton>
<form
role="search"
className="hidden md:flex flex-[100%] order-last lg:order-3 mt-2 lg:mt-0 pb-2 lg:pb-0"
onSubmit={search}
>
<SfInput
value={inputValue}
type="search"
className="[&::-webkit-search-cancel-button]:appearance-none"
placeholder="Search"
wrapperClassName="flex-1 h-10 pr-0"
size="base"
slotSuffix={
<span className="flex items-center">
<SfButton
variant="tertiary"
square
aria-label="search"
type="submit"
className="rounded-l-none hover:bg-transparent active:bg-transparent"
>
<SfIconSearch />
</SfButton>
</span>
}
onChange={(event) => setInputValue(event.target.value)}
/>
</form>
<nav className="flex-1 hidden md:flex justify-end lg:order-last lg:ml-4">
<div className="flex flex-row flex-nowrap">
{actionItems.map((actionItem) => (
<SfButton
key={actionItem.ariaLabel}
className="mr-2 -ml-0.5 rounded-md text-primary-700 hover:bg-primary-100 active:bg-primary-200 hover:text-primary-600 active:text-primary-700"
aria-label={actionItem.ariaLabel}
variant="tertiary"
square
slotPrefix={actionItem.icon}
>
{actionItem.role === 'login' && (
<p className="hidden xl:inline-flex whitespace-nowrap">{actionItem.label}</p>
)}
</SfButton>
))}
</div>
</nav>
</div>
</header>
);
}
NavbarTop with filled background and simple mobile bar
import { useState } from 'react';
import {
SfButton,
SfIconShoppingCart,
SfIconFavorite,
SfIconPerson,
SfIconExpandMore,
SfInput,
SfIconSearch,
SfIconMenu,
SfIconArrowBack,
} from '@storefront-ui/react';
export default function TopNavFilled() {
const [inputValue, setInputValue] = useState('');
const actionItems = [
{
icon: <SfIconShoppingCart />,
label: '',
ariaLabel: 'Cart',
role: 'button',
},
{
icon: <SfIconFavorite />,
label: '',
ariaLabel: 'Wishlist',
role: 'button',
},
{
label: 'Log in',
icon: <SfIconPerson />,
ariaLabel: 'Log in',
role: 'login',
},
];
const search = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
alert(`Successfully found 10 results for ${inputValue}`);
};
return (
<header className="flex justify-center w-full py-2 px-4 lg:py-5 lg:px-6 text-white border-0 bg-primary-700">
<div className="flex flex-wrap lg:flex-nowrap justify-between items-center flex-row md:justify-start h-full max-w-[1536px] w-full">
<SfButton variant="tertiary" square className="md:hidden text-white" aria-label="Go back">
<SfIconArrowBack />
</SfButton>
<a
href="#"
aria-label="SF Homepage"
className="inline-block mr-4 focus-visible:outline focus-visible:outline-offset focus-visible:rounded-sm shrink-0"
>
<img
src="https://storage.googleapis.com/sfui_docs_artifacts_bucket_public/production/vsf_logo_white.svg"
alt="Sf Logo"
className="w-[175px] md:h-6 md:w-[176px] lg:w-[12.5rem] lg:h-[1.75rem]"
/>
</a>
<SfButton variant="tertiary" square className="md:hidden text-white" aria-label="Search">
<SfIconSearch />
</SfButton>
<SfButton
aria-label="Open categories"
className="hidden md:block lg:hidden order-first lg:order-1 mr-4 text-white hover:text-white active:text-white hover:bg-primary-800 active:bg-primary-900"
square
variant="tertiary"
>
<SfIconMenu />
</SfButton>
<SfButton
className="hidden lg:flex lg:mr-4 text-white hover:text-white active:text-white hover:bg-primary-800 active:bg-primary-900"
variant="tertiary"
slotSuffix={<SfIconExpandMore className="hidden lg:block" />}
>
<span className="hidden lg:flex whitespace-nowrap">Browse products</span>
</SfButton>
<form
role="search"
className="hidden md:flex flex-[100%] order-last lg:order-3 mt-2 lg:mt-0 pb-2 lg:pb-0"
onSubmit={search}
>
<SfInput
value={inputValue}
type="search"
className="[&::-webkit-search-cancel-button]:appearance-none"
placeholder="Search"
wrapperClassName="flex-1 h-10 pr-0"
size="base"
slotSuffix={
<span className="flex items-center">
<SfButton
variant="tertiary"
square
aria-label="search"
type="submit"
className="rounded-l-none hover:bg-transparent active:bg-transparent"
>
<SfIconSearch />
</SfButton>
</span>
}
onChange={(event) => setInputValue(event.target.value)}
/>
</form>
<nav className="flex-1 hidden md:flex justify-end lg:order-last lg:ml-4">
<div className="flex flex-row flex-nowrap">
{actionItems.map((actionItem) => (
<SfButton
key={actionItem.ariaLabel}
className="mr-2 -ml-0.5 rounded-md text-white hover:text-white active:text-white hover:bg-primary-800 active:bg-primary-900"
aria-label={actionItem.ariaLabel}
variant="tertiary"
square
slotPrefix={actionItem.icon}
>
{actionItem.role === 'login' && (
<p className="hidden xl:inline-flex whitespace-nowrap">{actionItem.label}</p>
)}
</SfButton>
))}
</div>
</nav>
</div>
</header>
);
}