# Panel

> A lightweight surface for grouping related controls or metadata - the same BEM surface Card uses, but without header/footer ceremony.

- Category: data-display
- Status: stable (since 1.0.0)
- Tokens: --background-secondary, --foreground-primary, --foreground-info, --foreground-danger, --cta-background
- Playground: https://design.freecodecamp.org/playground#panel
- npm dependencies: `react@>=18 <20`
- Registry dependencies: [theme](https://design.freecodecamp.org/registry/theme.md)
- Files:
  - `Panel.tsx` → `src/ui/panel/Panel.tsx` (raw: https://design.freecodecamp.org/registry/panel/Panel.tsx)
  - `panel.css` → `src/ui/panel/panel.css` (raw: https://design.freecodecamp.org/registry/panel/panel.css)

## Install (copy source)

1. Ensure the theme is installed once per project - tokens.css + base.css imported globally, fonts available. See https://design.freecodecamp.org/registry/theme.md and https://design.freecodecamp.org/registry/starter.md.
2. Copy the files below into `src/ui/panel/` (adjust to your project layout) and import the CSS once from your global stylesheet, e.g. `@import './ui/panel/panel.css';`.
3. Colors, spacing and type come from tokens - tailor the component by editing the copied source; recolour by editing tokens.css, not the component CSS.

## Usage

Panels are the minimum surface for grouping controls inside a page. They
offer the tinted background of a Card without the header/footer ceremony.

## Usage

```tsx
import { Panel } from './ui/panel/Panel';
<Panel title='Shortcuts' variant='info'>
  Press <kbd>/</kbd> to open search from anywhere in the docs.
</Panel>;
```

## Accessibility

Renders as a `<div>`. If the panel conveys region semantics, wrap it in
a native landmark (`<section aria-labelledby>`) or add `role='region'`
yourself. Panels default to no role because they are often decorative.

## Example

```tsx
import { Panel } from './ui/panel/Panel';

<Panel title="Editor hints">
  Your code runs against the first test each time you save.
</Panel>
```

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `variant` | `enum` | no | `default` |  |
| `title` | `ReactNode` | no | - |  |

## Source: Panel.tsx

```tsx
import React, { forwardRef } from 'react';

export type PanelVariant = 'default' | 'primary' | 'danger' | 'info';

export interface PanelProps extends Omit<
  React.HTMLAttributes<HTMLDivElement>,
  'title'
> {
  variant?: PanelVariant;
  title?: React.ReactNode;
}

export const Panel = forwardRef<HTMLDivElement, PanelProps>(
  ({ variant = 'default', title, className = '', children, ...rest }, ref) => {
    const classes = [
      'panel',
      variant !== 'default' && `panel--${variant}`,
      className
    ]
      .filter(Boolean)
      .join(' ');
    return (
      <div ref={ref} className={classes} {...rest}>
        {title !== undefined && <p className='panel__heading'>{title}</p>}
        <div className='panel__body'>{children}</div>
      </div>
    );
  }
);
Panel.displayName = 'Panel';
```

## Source: panel.css

```css
.panel {
  border: 1px solid var(--background-quaternary);
  background: var(--background-primary);
  margin: 0 0 24px;
}
.panel__heading {
  padding: 10px 16px;
  background: var(--background-secondary);
  border-bottom: 1px solid var(--background-quaternary);
  font-weight: 700;
  margin: 0;
}
.panel__body {
  padding: 16px;
  margin: 0;
}
.panel--primary {
  border-color: var(--foreground-primary);
}
.panel--primary .panel__heading {
  color: var(--foreground-primary);
  background: transparent;
  border-bottom-color: var(--foreground-primary);
}
.panel--danger {
  border-color: var(--danger-color);
}
.panel--danger .panel__heading {
  background: var(--danger-color);
  color: var(--danger-background);
}
.panel--info {
  border-color: var(--highlight-color);
}
.panel--info .panel__heading {
  background: var(--highlight-color);
  color: var(--highlight-background);
}
```

## HTML / vanilla variant

```html
<div class="panel">
  <p class="panel__heading">Editor hints</p>
  <p class="panel__body">Your code runs against the first test each time you save.</p>
</div>
```

Interactive behaviours for plain HTML come from the vanilla runtime (data-uikit-* attributes): https://design.freecodecamp.org/registry/vanilla.md - or download https://design.freecodecamp.org/cdn/uikit.global.js once and self-host it (do not hotlink).

## For coding agents

This library is distributed as copyable source, not an npm package. Start at https://design.freecodecamp.org/registry/starter.md, discover components via https://design.freecodecamp.org/llms.txt, and copy files into the consuming project. Keep token names intact; recolour by editing the copied tokens.css.
