@hackplan/polaris
Version:
Shopify’s product component library
431 lines (358 loc) • 14.6 kB
Markdown
name: Top bar
category: Structure
keywords:
- global chrome
- global features
- topbar
- top bar
- nav bar
- bar
- navbar
- brand
- search
- user
- menu
- logo
# Top bar
Merchants can use the top bar component to search, access menus, and navigate by clicking on the logo. It’s always visible at the top of non-embedded interfaces like Shopify or Shopify Plus. Third-party apps that use the top bar can customize the color to match their brand using the [app provider](/components/structure/app-provider) component and are required to use their own logo.
## Component dependencies
The top bar component must be passed to the [frame](/components/structure/frame) component.
## Best practices
The top bar component should:
- Not provide global navigation for an application
- Use the [navigation component](/components/structure/navigation) instead
- Include search to help merchants find resources and navigate an application
- Include a user menu component to indicate the logged-in merchant and provide them with global actions
- Provide a color through the [app provider](/components/structure/app-provider) component to style the background
- The global menu text should contrast with the rest of the top bar and pass the minimum contrast ratio of the WCAG 2.0 guidelines
- Use an SVG file for the logo
- Use a logo that passes the minimum contrast ratio of the WCAG 2.0 guidelines when compared to the top bar background color
- Show the navigation toggle so it appears on small screen
## Content guidelines
### Placeholder content
The placeholder content for the search field should:
- Always say "Search"
- Never include an ellipsis
<!-- usagelist -->
#### Do
- Search
#### Don’t
- search...
<!-- end -->
<a name="subcomponent-menu"></a>
## Top bar menu
A component that composes together an activator and a popover containing an action list to create a dropdown menu.
### Menu properties
| Prop | Type | Description |
| ---------------- | ----------------------------- | -------------------------------------------------------------------------------------------------- |
| activatorContent | React.ReactNode | Accepts an activator component that renders inside of a button that opens the menu |
| actions | ActionListProps['sections'] | An array of action objects that are rendered inside of a popover triggered by this menu |
| message | [MessageProps](#type-message) | Accepts a message that facilitates direct, urgent communication with the merchant through the menu |
| open | boolean | A boolean property indicating whether the menu is currently open |
| onOpen() | function | A callback function to handle opening the menu popover |
| onClose() | function | A callback function to handle closing the menu popover |
<a name="subcomponent-user-menu"></a>
## Top bar user menu
A specialized menu component that is activated by a user avatar.
### Menu properties
| Prop | Type | Description |
| ---------- | ----------------------------- | ------------------------------------------------------------------------------------------------------- |
| actions | {items: IconableAction[]}[] | An array of action objects that are rendered inside of a popover triggered by this menu |
| message | [MessageProps](#type-message) | Accepts a message that facilitates direct, urgent communication with the merchant through the user menu |
| name | string | A string detailing the merchant’s full name to be displayed in the user menu |
| detail | string | A string allowing further details on the merchant’s name displayed in the user menu |
| initials | AvatarProps['initials'] | The merchant’s initials, rendered in place of an avatar image when not provided |
| avatar | AvatarProps['source'] | An avatar image representing the merchant |
| open | boolean | A boolean property indicating whether the user menu is currently open |
| onToggle() | function | A callback function to handle opening and closing the user menu |
<a name="type-message"></a>
### Top bar menu message
#### Message properties
| Prop | Type | Description |
| ----------- | ----------------------------------------------- | ----------------------------------------- |
| title | string | A title for the message |
| description | string | A description for the message |
| action | {onClick(): void; content: string} | An action to render near the message |
| link | {to: string; content: string} | A link to view the content of the message |
| badge | {content: string; status: BadgeProps['status']} | A badge to render near the message |
<a name="subcomponent-search-field"></a>
## Top bar search field
A text field component that is tailor-made for a search use-case.
### Search field properties
| Prop | Type | Description |
| ----------------------- | -------- | -------------------------------------------------------------------------------- |
| value | string | Initial value for the input |
| placeholder | string | Hint text to display |
| focused | boolean | Force the focus state on the input |
| active | boolean | Force a state where search is active but the text field component is not focused |
| onChange(value: string) | function | Callback when value is changed |
| onFocus() | function | Callback when input is focused |
| onBlur() | function | Callback when focus is removed |
## Examples
### Top bar with all of its elements
Use to provide structure for the top of an application. Style the top bar component using the app provider component with a theme. Providing just the `background` key for the top bar component theme will result in intelligent defaults being set for complementary colors with contrasting text.
```jsx
class TopBarExample extends React.Component {
state = {
userMenuOpen: false,
searchActive: false,
searchText: '',
};
render() {
const {
state,
handleSearchChange,
handleSearchResultsDismiss,
toggleUserMenu,
} = this;
const {userMenuOpen, searchText, searchActive} = state;
const theme = {
colors: {
topBar: {
background: '#357997',
},
},
logo: {
width: 124,
topBarSource:
'https://cdn.shopify.com/s/files/1/0446/6937/files/jaded-pixel-logo-color.svg?6215648040070010999',
url: 'http://jadedpixel.com',
accessibilityLabel: 'Jaded Pixel',
},
};
const userMenuMarkup = (
<TopBar.UserMenu
actions={[
{
items: [{content: 'Back to Shopify', icon: ArrowLeftMinor}],
},
{
items: [{content: 'Community forums'}],
},
]}
name="Dharma"
detail="Jaded Pixel"
initials="D"
open={userMenuOpen}
onToggle={toggleUserMenu}
/>
);
const searchResultsMarkup = (
<Card>
<ActionList
items={[
{content: 'Shopify help center'},
{content: 'Community forums'},
]}
/>
</Card>
);
const searchFieldMarkup = (
<TopBar.SearchField
onChange={handleSearchChange}
value={searchText}
placeholder="Search"
/>
);
const topBarMarkup = (
<TopBar
showNavigationToggle={true}
userMenu={userMenuMarkup}
searchResultsVisible={searchActive}
searchField={searchFieldMarkup}
searchResults={searchResultsMarkup}
onSearchResultsDismiss={handleSearchResultsDismiss}
onNavigationToggle={() => {
console.log('toggle navigation visibility');
}}
/>
);
return (
<div style={{height: '250px'}}>
<AppProvider
theme={theme}
i18n={{
Polaris: {
Avatar: {
label: 'Avatar',
labelWithInitials: 'Avatar with initials {initials}',
},
Frame: {skipToContent: 'Skip to content'},
TopBar: {
toggleMenuLabel: 'Toggle menu',
SearchField: {
clearButtonLabel: 'Clear',
search: 'Search',
},
},
},
}}
>
<Frame topBar={topBarMarkup} />
</AppProvider>
</div>
);
}
toggleUserMenu = () => {
this.setState(({userMenuOpen}) => ({userMenuOpen: !userMenuOpen}));
};
handleSearchResultsDismiss = () => {
this.setState(() => {
return {
searchActive: false,
searchText: '',
};
});
};
handleSearchChange = (value) => {
this.setState({searchText: value});
if (value.length > 0) {
this.setState({searchActive: true});
} else {
this.setState({searchActive: false});
}
};
}
```
### Top bar themed with keys
Provide specific keys and corresponding colors to the top bar theme for finer control. When giving more than just the `background`, providing all keys is necessary to prevent falling back to default colors.
```jsx
class TopBarExample extends React.Component {
state = {
userMenuOpen: false,
searchActive: false,
searchText: '',
};
render() {
const {
state,
handleSearchChange,
handleSearchResultsDismiss,
toggleUserMenu,
} = this;
const {userMenuOpen, searchText, searchActive} = state;
const theme = {
colors: {
topBar: {
background: '#357997',
backgroundLighter: '#6192a9',
color: '#FFFFFF',
},
},
logo: {
width: 124,
topBarSource:
'https://cdn.shopify.com/s/files/1/0446/6937/files/jaded-pixel-logo-color.svg?6215648040070010999',
url: 'http://jadedpixel.com',
accessibilityLabel: 'Jaded Pixel',
},
};
const userMenuMarkup = (
<TopBar.UserMenu
actions={[
{
items: [{content: 'Back to Shopify', icon: ArrowLeftMinor}],
},
{
items: [{content: 'Community forums'}],
},
]}
name="Dharma"
detail="Jaded Pixel"
initials="D"
open={userMenuOpen}
onToggle={toggleUserMenu}
/>
);
const searchResultsMarkup = (
<Card>
<ActionList
items={[
{content: 'Shopify help center'},
{content: 'Community forums'},
]}
/>
</Card>
);
const searchFieldMarkup = (
<TopBar.SearchField
onChange={handleSearchChange}
value={searchText}
placeholder="Search"
/>
);
const topBarMarkup = (
<TopBar
showNavigationToggle={true}
userMenu={userMenuMarkup}
searchResultsVisible={searchActive}
searchField={searchFieldMarkup}
searchResults={searchResultsMarkup}
onSearchResultsDismiss={handleSearchResultsDismiss}
onNavigationToggle={() => {
console.log('toggle navigation visibility');
}}
/>
);
return (
<div style={{height: '250px'}}>
<AppProvider
theme={theme}
i18n={{
Polaris: {
Frame: {skipToContent: 'Skip to content'},
Avatar: {
label: 'Avatar',
labelWithInitials: 'Avatar with initials {initials}',
},
TopBar: {
toggleMenuLabel: 'Toggle menu',
SearchField: {
clearButtonLabel: 'Clear',
search: 'Search',
},
},
},
}}
>
<Frame topBar={topBarMarkup} />
</AppProvider>
</div>
);
}
toggleUserMenu = () => {
this.setState(({userMenuOpen}) => ({userMenuOpen: !userMenuOpen}));
};
handleSearchResultsDismiss = () => {
this.setState(() => {
return {
searchActive: false,
searchText: '',
};
});
};
handleSearchChange = (value) => {
this.setState({searchText: value});
if (value.length > 0) {
this.setState({searchActive: true});
} else {
this.setState({searchActive: false});
}
};
}
```
## Related components
- To provide the structure for the top bar component, as well as the primary navigation use the [frame](/components/structure/frame) component.
- To display the primary navigation within the frame of a non-embedded application, use the [navigation](/components/structure/navigation) component.
- To tell merchants their options once they have made changes to a form on the page use the [contextual save bar](/components/forms/contextual-save-bar) component.
- To provide quick, at-a-glance feedback on the outcome of an action, use the [toast](/components/feedback-indicators/toast) component.
- To indicate to merchants that a page is loading or an upload is processing use the [loading](/components/feedback-indicators/loading) component.