# TallStackUI: Key-Value
> TallStackUI is a TALL Stack (Tailwind CSS, Alpine.js, Laravel, Livewire)
> component library providing 80+ Blade components for building modern web interfaces.
> **Requires Livewire:** This component must be used within a Livewire component.
A dynamic key-value pair editor that allows users to add, edit, and remove entries. Syncs data with a Livewire property via wire:model. Supports static (read-only) mode, row limits, deletable rows, and an accent color on the header and the add button.
## Basic Usage
```blade
```
```blade
```
```blade
```
```blade
```
```blade
```
## Attributes
| Attribute | Type | Default | Description |
|---------------|-----------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------|
| label | string\|null | null | Custom header label for the key column (defaults to translation) |
| value | string\|null | null | Custom header label for the value column (defaults to translation) |
| color | string\|null | null | Accent for the header and the add button. Any TallStackUI color, or `black`. Without it the header stays neutral and the button follows `primary`. |
| colorless | bool\|null | null | Drops the accent entirely, in light and dark. Wins over `color`. |
| compact | bool | false | Tightens the vertical padding of the header, the rows, the empty message and the add button |
| limit | int\|null | null | Maximum number of rows allowed |
| static | bool | null | Makes all inputs read-only and hides the add button |
| deletable | bool | null | Shows a delete button on each row |
| delete-method | string\|null | null | Livewire method name to call when a row is deleted |
| placeholders | bool | true | Shows placeholder text in the key and value inputs |
| icon | ComponentSlot\|string\|null | null | Custom icon for the delete button (defaults to 'trash'), or a slot for fully custom delete markup |
## Compact
`compact` tightens the vertical padding so more pairs fit on a screen. It reaches the
header, the rows, the empty message and the add button; the horizontal padding, the type
scale and the colors are untouched. A compact row carries the same `py-2.5` as a compact
`` data cell, so the two share a rhythm on a page holding both.
```blade
```
It works with everything else — `color`, `colorless`, `limit`, `static`, `deletable`.
`deletable` rows are the one exception: they already carry no vertical padding, because
the delete button is absolutely positioned against the row and the padding was dropped to
make room for it. `compact` still tightens the header, the empty message and the add
button on such a component.
Each affected block has a `-compact` twin, and `compact` swaps the whole string rather
than layering on top of it. Customizing `header.wrapper` therefore leaves a compact
component alone; customize `header.wrapper-compact` as well when both modes are in use.
## Slots
| Slot | Description |
|--------|-----------------------------------------------------------------------|
| header | Custom content appended to the header row |
| icon | Custom markup for the delete button (replaces the default trash icon) |
## Alpine.js Events
| Event | Description |
|-------------|-------------------------------|
| x-on:add | Fires when a new row is added |
| x-on:remove | Fires when a row is removed |
Both events carry the rows in `$event.detail.rows`, each one as `{ key, value }`.
## Server Changes
The rows follow the property both ways. A change made on the server after the first render, such as `$this->reset('metadata')` once a record is saved or a list loaded into the property by an edit action, replaces the rows on screen. The property only ever holds `key` and `value` for each row.
## Validation Constraints
- The `static` and `limit` attributes cannot be used at the same time.
## Soft Customization
Soft customization allows you to override default Tailwind CSS classes used by this component at runtime, either through a service provider or scoped per-instance.
### Customization
```php
TallStackUi::customize()
->keyValue()
->block('wrapper', 'your-tailwind-classes');
```
### Available Blocks
| Block Name | Purpose |
|--------------------------------------|----------------------------------------------------------------------------|
| wrapper | Outer container styles (background, border, rounded corners) |
| header.wrapper | Header row layout (grid, border, padding) |
| header.wrapper-compact | Header used instead of `header.wrapper` under `compact` |
| header.neutral | Header text color, applied when no accent resolves |
| header.key | Header key column text style |
| header.value | Header value column text style |
| empty.wrapper | Empty state container (centered flex) |
| empty.wrapper-compact | Empty state used instead of `empty.wrapper` under `compact` |
| empty.text | Empty state message text style |
| list.wrapper | Row layout for each key-value pair |
| list.wrapper-default-padding | Row vertical padding, applied when `deletable` is off |
| list.wrapper-default-padding-compact | Row padding used instead of `list.wrapper-default-padding` under `compact` |
| list.input.key | Input styles for the key field |
| list.input.value | Input styles for the value field |
| button.add | Add row button layout (full-width, border, padding) |
| button.add-compact | Add row button used instead of `button.add` under `compact` |
| button.neutral | Add row button color under `colorless` |
| button.delete | Delete icon button styles (positioning, color) |
## Color Personalization
```bash
php artisan tallstackui:setup-color
```
Publishes a `KeyValueColors` class with two palettes: `headerColors()` for the header text
and `buttonColors()` for the add button. Returning `null` for an entry falls back to the
bundled value, so only the colors you actually change need filling in.
The button reads its palette whether or not `color` is given, falling back to `primary`.
The header only reads its own when a color is asked for, since it is a caption rather than
an action.
`colorless` short-circuits both, handing the header and the button back to
`header.neutral` and `button.neutral`. A color and a neutral never land on the same
element, which is why neither has to out-specify the other.