Banner
A full-width strip for a state that covers everything below it: the whole app when you are offline, or a whole record when it is archived or must not be contacted. The largest of three message levels.
Playground
Change the controls to try each prop. The code under the preview updates as you go and lists only the props you changed; copy it into your page.
import { Banner } from '@/ui/banner';<Banner title=""> Hidden from lists and search. Its history stays.</Banner>Warning, app-wide
The offline strip sits above the sidebar and the page, centred, until the connection is back. Then it goes without a toast. OfflineBanner draws it from one prop, online, which the app shell takes from the browser's online and offline events; it is announced once as it appears. Press the button to drop and restore the connection. For any other app-wide strip, pass global for the 36px centred strip.
import { useState } from 'react';
import { OfflineBanner } from '@/ui/banner';
import { Button } from '@/ui/button';
// The app shell passes `online` from the browser's online and offline events. Press the button to drop the connection.
export default function BannerOffline() {
const [online, setOnline] = useState(false);
return (
<div className="flex w-full flex-col items-start gap-200">
<OfflineBanner online={online} />
<Button size="sm" onClick={() => setOnline(!online)}>
{online ? 'Go offline' : 'Back online'}
</Button>
</div>
);
}Neutral
A whole record is in a lasting state, such as archived. The strip sits directly under the record's header, edge to edge, on the current grey. A bold label first, one sentence after, one action at most.
import { ArchiveIcon } from '@phosphor-icons/react';
import { Banner } from '@/ui/banner';
import { Button } from '@/ui/button';
export default function BannerArchived() {
return (
<Banner icon={<ArchiveIcon />} title="Archived" action={<Button size="sm">Restore</Button>}>
Hidden from lists and search. Its history stays.
</Banner>
);
}Error
A rule the whole record must follow, such as Do not contact.
import { Banner } from '@/ui/banner';
export default function BannerDoNotContact() {
return (
<Banner appearance="error" title="Do not contact">
Daniel asked not to be contacted. Don’t email or call him about roles.
</Banner>
);
}Information
A fact about the whole record that the person should know before acting.
import { Banner } from '@/ui/banner';
export default function BannerInformation() {
return (
<Banner appearance="information" title="Imported">
This company came from your Bullhorn import. Check its owner before you contact it.
</Banner>
);
}Next step
The one thing waiting on a Job, at the top of the Job page, on the selected fill with a brand dot. When nothing waits, show no banner.
import { Banner } from '@/ui/banner';
import { Button } from '@/ui/button';
export default function BannerNext() {
return (
<Banner appearance="next" title="Next:" action={<Button size="sm" variant="primary">Review applicants</Button>}>
3 applicants to review for Senior Data Engineer
</Banner>
);
}Tooltip
A short label that appears on hover or focus: the name of an icon button, its shortcut, or the full text of something clipped. It never holds anything the person must read to finish a task.
Connection status
Whether Ascern can still read a member's mail, calendar or meetings, when it last did, and the one thing to do about it. A row in Settings, a dot in the account menu, a banner across the app while it needs action.