# Tabs

Zero-JavaScript tabbed content panels with CSS custom property theming.

> For the index of this section of the site, see [llms.txt](https://better-static-sites.github.io/llms.txt)

# Tabs

Tabbed content panels for MDX pages. No client-side JavaScript: reorganizes the DOM at build time for label styling, panel switching uses CSS `:has()`.

Current version: **1.0.0** --[npm](https://www.npmjs.com/package/astro-better-tabs)

## Installation

```shell-session
$ npm install astro-better-tabs
```

Import the CSS in your global stylesheet:

```css
@import "astro-better-tabs/style.css";
```

## Usage

```jsx
import Tabs from 'astro-better-tabs/Tabs.astro';
import TabItem from 'astro-better-tabs/TabItem.astro';

<Tabs>
  <TabItem label="npm">
    ```shell-session
    npm install my-package
    ```
  </TabItem>
  <TabItem label="yarn">
    ```shell-session
    yarn add my-package
    ```
  </TabItem>
  <TabItem label="pnpm">
    ```shell-session
    pnpm add my-package
    ```
  </TabItem>
</Tabs>
```

## Live example

```shell-session
$ npm install astro-better-tabs
```

```shell-session
$ yarn add astro-better-tabs
```

```shell-session
$ pnpm add astro-better-tabs
```

## Tabs props

No props.

## TabItem props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | (required) | Tab button text. Supports inline markdown. |

## How it works

`TabItem` outputs a `<div class="tab-bar-item">` wrapper (containing a hidden `<input type="radio">` and a `<label>`) followed by a `<div class="tab-panel">`.

`Tabs` renders the slot HTML and does two build-time string passes:

1.  Injects a unique `name` into every radio input and marks the first `checked`.
2.  Extracts all `tab-bar-item` wrappers and places their inputs and labels into a `<nav class="tab-bar">` prepended to the output. Panels remain as direct `<div>` children of `.tabs-group` after the nav.

Panel visibility is handled by pre-generated CSS `:has()` rules (supports up to 12 tabs):

```css
.tabs-group:has(> .tab-bar > .tab-input:nth-of-type(1):checked) > .tab-panel:nth-of-type(1) { display: block; }
.tabs-group:has(> .tab-bar > .tab-input:nth-of-type(2):checked) > .tab-panel:nth-of-type(2) { display: block; }
/* ... up to 12 */
```

`:has()` requires Chrome 105+, Firefox 121+, or Safari 15.4+.

## Styling

This component requires Tailwind CSS in the consuming project. Import the stylesheet and tell Tailwind to scan the component files:

```css
@import "astro-better-tabs/style.css";
@source "../../node_modules/astro-better-tabs/Tabs.astro";
@source "../../node_modules/astro-better-tabs/TabItem.astro";
```

The component exposes CSS custom properties on `.tabs-group` for theming:

| Property | Controls |
| --- | --- |
| `--tabs-bg` | tab bar background |
| `--tabs-border` | container border |
| `--tabs-panel-bg` | content panel background |
| `--tabs-active-bg` | active tab label background |
| `--tabs-active-color` | active tab label text color |

Override to match your brand:

```css
/* light mode */
.tabs-group {
  --tabs-border:       #e5e7eb;
  --tabs-bg:           #f9fafb;
  --tabs-active-bg:    #ffffff;
  --tabs-active-color: #7c3aed;
}

/* dark mode */
.dark .tabs-group {
  --tabs-border:       #1c0e00;
  --tabs-bg:           #111111;
  --tabs-panel-bg:     #080808;
  --tabs-active-bg:    #080808;
  --tabs-active-color: #fb923c;
}
```