# Project Banner

Used for temporary, project-wide notifications that require resolution

---

## Default

```tsx
import { ProjectBanner } from '@vercel/geistcn/components';
import { IconShieldCheck } from '@vercel/geistcn-assets/icons';
import type { JSX } from 'react';

export function Component(): JSX.Element {
  return (
    <ProjectBanner
      callToAction={{
        label: 'Disable',
        href: `/`,
      }}
      icon={<IconShieldCheck className="shrink-0" />}
      label={<>Attack Challenge Mode is enabled for this project</>}
    />
  );
}
```

## Success

For positive, temporary mitigations put in place to protect a project, e.g., Attack Challenge Mode

```tsx
import type { ProjectBannerProps } from '@vercel/geistcn/components';
import { ProjectBanner } from '@vercel/geistcn/components';
import { ShieldCheck } from '@vercel/geistcn/icons';
import type { JSX } from 'react';

const ProjectBannerVariants: ProjectBannerProps['variant'][] = ['success'];

export function Component(): JSX.Element {
  return (
    <div className="flex flex-col items-stretch justify-start gap-6 flex-initial">
      {ProjectBannerVariants.map((variant) => {
        return (
          <div
            key={variant}
            className="flex flex-col items-stretch justify-start gap-2 flex-initial"
          >
            <div className="flex flex-col items-stretch justify-start gap-2 flex-initial">
              <ProjectBanner
                callToAction={{
                  label: 'Disable',
                  href: `/`,
                }}
                icon={<ShieldCheck className="shrink-0" />}
                label={<>Attack Challenge Mode is enabled for this project</>}
                variant={variant}
              />
            </div>
          </div>
        );
      })}
    </div>
  );
}
```

## Warning

When a project is in an exceptional state which requires non-immediate action to exit, e.g., during a rollback

```tsx
import type { ProjectBannerProps } from '@vercel/geistcn/components';
import { ProjectBanner, Tooltip } from '@vercel/geistcn/components';
import { RotateCounterClockwise } from '@vercel/geistcn/icons';
import type { JSX } from 'react';

const ProjectBannerVariants: ProjectBannerProps['variant'][] = ['warning'];

export function Component(): JSX.Element {
  return (
    <div className="flex flex-col items-stretch justify-start gap-6 flex-initial">
      {ProjectBannerVariants.map((variant) => {
        return (
          <div
            key={variant}
            className="flex flex-col items-stretch justify-start gap-2 flex-initial"
          >
            <div className="flex flex-col items-stretch justify-start gap-2 flex-initial">
              <ProjectBanner
                callToAction={{
                  label: 'Undo Rollback',
                  onClick: () => {
                    alert('Button clicked');
                  },
                }}
                icon={<RotateCounterClockwise />}
                label={
                  <>
                    This project was rolled back by{' '}
                    <Tooltip
                      className="underline decoration-dashed underline-offset-[5px]"
                      text="Yesterday for project marketing-website"
                    >
                      @johnphamous
                    </Tooltip>
                  </>
                }
                variant={variant}
              />
            </div>
          </div>
        );
      })}
    </div>
  );
}
```

## Error

When a project is approaching or experiencing critical downtime which requires immediate attention, e.g., when payment is overdue

```tsx
import type { ProjectBannerProps } from '@vercel/geistcn/components';
import { ProjectBanner } from '@vercel/geistcn/components';
import { Warning } from '@vercel/geistcn/icons';
import type { JSX } from 'react';

const ProjectBannerVariants: ProjectBannerProps['variant'][] = ['error'];

export function Component(): JSX.Element {
  return (
    <div className="flex flex-col items-stretch justify-start gap-6 flex-initial">
      {ProjectBannerVariants.map((variant) => {
        return (
          <div
            key={variant}
            className="flex flex-col items-stretch justify-start gap-2 flex-initial"
          >
            <div className="flex flex-col items-stretch justify-start gap-2 flex-initial">
              <ProjectBanner
                callToAction={{
                  label: 'Add Credit Card',
                  href: `/$`,
                }}
                icon={<Warning />}
                label={
                  <>
                    Payment failed, update credit card information before your
                    account is shut down
                  </>
                }
                variant="error"
              />
            </div>
          </div>
        );
      })}
    </div>
  );
}
```

## Best Practices

### When to use

* Use Project Banner for project-wide states that need resolution: overdue billing, an active rollback, attack mitigation, an expiring trial blocking deploys.
* Pick `Note` for inline contextual messages tied to a single field or card, `Toast` for transient acknowledgments, `Modal` for confirmations.
* Match `variant` to severity: `error` for critical downtime or payment-blocking states, `warning` for an exceptional state with non-immediate action, `success` for a positive temporary mitigation, `gray` for routine project-wide notices.

### Behavior

* Project Banner is non-dismissible by design. If the message can be dismissed without resolving the underlying state, it isn’t banner-worthy; move it to a `Note`.
* Show one Project Banner at a time. Stacking competing banners drowns the most urgent state.
* Always pass a `callToAction` that resolves the state. A banner with no route is a dead end.

### Content

* `label` is one sentence in sentence case that names the impact: `Your Pro trial expires in 3 days.` Don’t open with `Heads up` or apologetic preambles.
* `callToAction.label` is Title Case `Verb + Noun` and points at the resolver: `Update Payment Method`, `Reactivate Project`, `Review Tokens`.
* Name the affected entity when the project context isn’t obvious from the surrounding chrome (`Production deployments are paused on my-project`).
* Don’t encode severity in the copy with emoji or interjections; the variant carries that signal.
