> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blockli.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Block Options: Configuring Editor-Controlled Behavior

> Add configurable options to blökkli blocks. Options appear in the editor sidebar and let content editors customize each block's appearance and behavior.

Block options give content editors control over a block's appearance and behaviour directly from the editor's options panel. You define options inside `defineBlokkli()` and read their current values through the reactive `options` object it returns. Changes made in the editor are reflected instantly in the rendered block — no save or reload required.

## Defining Options

Pass an `options` object to `defineBlokkli()`. Each key becomes an option name; the value is an option definition that describes the input type, display label, and default value:

```typescript theme={null}
const { options } = defineBlokkli({
  bundle: 'banner',
  options: {
    theme: {
      type: 'radios',
      label: 'Theme',
      default: 'primary',
      options: {
        primary: 'Primary',
        secondary: 'Secondary',
        warning: 'Warning',
      },
    },
    showCloseButton: {
      type: 'checkbox',
      label: 'Show close button',
      default: false,
    },
    maxWidth: {
      type: 'number',
      label: 'Max width (px)',
      default: 1200,
    },
  },
})
```

Access the values in your template via the reactive `options` object:

```vue theme={null}
<template>
  <div
    :class="`banner banner--${options.theme}`"
    :style="{ maxWidth: `${options.maxWidth}px` }"
  >
    <button v-if="options.showCloseButton">×</button>
    <slot />
  </div>
</template>
```

<Tip>
  TypeScript users get full type inference on the `options` object — the types of each property are inferred from the option definitions you provide, including string unions for `radios` and `checkboxes` options.
</Tip>

## Option Types

### `text`

A single-line text input. Use it for short freeform values like button labels, override headings, or custom identifiers.

```typescript theme={null}
myOption: {
  type: 'text',
  label: 'Button text',
  default: 'Learn more',
}
// Value type: string
```

***

### `checkbox`

A boolean toggle rendered as a checkbox. The value is `true` when checked and `false` (or `undefined` if unset) when not.

```typescript theme={null}
myOption: {
  type: 'checkbox',
  label: 'Show border',
  default: false,
}
// Value type: boolean | undefined
```

***

### `checkboxes`

A multi-select input where editors can pick any combination of the defined choices. The returned value is an array of the selected keys.

```typescript theme={null}
myOption: {
  type: 'checkboxes',
  label: 'Features',
  default: [],
  options: {
    search: 'Search',
    sort: 'Sort',
    filter: 'Filter',
  },
}
// Value type: string[]
```

Use `v-for` or `.includes()` checks in your template to act on the selected values:

```vue theme={null}
<ul>
  <li v-if="options.features.includes('search')">🔍 Search</li>
  <li v-if="options.features.includes('sort')">↕ Sort</li>
  <li v-if="options.features.includes('filter')">⚙ Filter</li>
</ul>
```

***

### `radios`

A single-select input where editors pick exactly one of the defined choices. The returned value is the key of the selected option.

```typescript theme={null}
myOption: {
  type: 'radios',
  label: 'Column count',
  default: '3',
  displayAs: 'grid',
  options: {
    '1': '1 col',
    '2': '2 cols',
    '3': '3 cols',
    '4': '4 cols',
  },
}
// Value type: string (key of selected option)
```

Use the optional `displayAs` property to control how the choices are rendered in the editor panel:

| `displayAs` value | Appearance                                                   |
| ----------------- | ------------------------------------------------------------ |
| `'radios'`        | Standard radio button list (default)                         |
| `'grid'`          | Compact grid of buttons — good for numeric or short values   |
| `'colors'`        | Colour swatches — use when option keys are CSS colour values |
| `'icons'`         | Icon button grid — use when options map to icon names        |

***

### `color`

An HTML colour picker that returns a hex string. Use it for background colours, text colours, or any CSS colour value that editors should control.

```typescript theme={null}
myOption: {
  type: 'color',
  label: 'Background color',
  default: '#ffffff',
}
// Value type: '#rrggbb' hex string
```

```vue theme={null}
<section :style="{ backgroundColor: options.bgColor }">
  <!-- content -->
</section>
```

***

### `range`

A slider input for selecting a value within a numeric range. Ideal for spacing scales, opacity, border radius, or any value where approximate adjustment is more important than precision.

```typescript theme={null}
myOption: {
  type: 'range',
  label: 'Opacity',
  default: 100,
  min: 0,
  max: 100,
}
// Value type: number
```

***

### `number`

A direct numeric input field. Use it when precision matters and a slider would be cumbersome — for example, an exact pixel value or an item count.

```typescript theme={null}
myOption: {
  type: 'number',
  label: 'Items per row',
  default: 3,
  min: 1,
  max: 6,
}
// Value type: number
```

<Note>
  Both `range` and `number` accept `min` and `max` constraints. blökkli enforces these bounds in the editor UI — editors cannot enter values outside the declared range.
</Note>

## Grouping Options

Add a `group` string to any option definition to cluster related options under a labelled section heading in the options panel. Options without a `group` appear in a default ungrouped section.

```typescript theme={null}
const { options } = defineBlokkli({
  bundle: 'promo_card',
  options: {
    heading: {
      type: 'text',
      label: 'Heading',
      group: 'Content',
      default: '',
    },
    body: {
      type: 'text',
      label: 'Body text',
      group: 'Content',
      default: '',
    },
    bgColor: {
      type: 'color',
      label: 'Background',
      group: 'Style',
      default: '#ffffff',
    },
    padding: {
      type: 'range',
      label: 'Padding',
      group: 'Style',
      default: 4,
      min: 0,
      max: 10,
    },
  },
})
```

This produces two collapsible sections in the editor — **Content** and **Style** — making complex blocks much easier to navigate.

## Global Options

For options that apply to many blocks (for example, a site-wide spacing scale or colour scheme), define them once in `nuxt.config.ts` and reference them by key using the `globalOptions` array:

```typescript theme={null}
// nuxt.config.ts
export default defineNuxtConfig({
  blokkli: {
    globalOptions: {
      spacing: {
        type: 'radios',
        label: 'Spacing',
        default: 'md',
        options: {
          sm: 'Small',
          md: 'Medium',
          lg: 'Large',
        },
      },
      colorScheme: {
        type: 'radios',
        label: 'Color scheme',
        default: 'light',
        options: {
          light: 'Light',
          dark: 'Dark',
        },
      },
    },
  },
})
```

Then reference them in any block:

```typescript theme={null}
const { options } = defineBlokkli({
  bundle: 'section',
  globalOptions: ['spacing', 'colorScheme'],
})
```

<Tip>
  Global options are merged into the same `options` reactive object alongside any local options. You access them the same way — `options.spacing`, `options.colorScheme` — no extra steps required.
</Tip>

## Full Example

Here is a complete block that uses a range of option types and grouping:

<CodeGroup>
  ```vue Component theme={null}
  <!-- components/Blokkli/PricingCard.vue -->
  <template>
    <div
      :class="[
        'pricing-card',
        `pricing-card--${options.style}`,
        { 'pricing-card--featured': options.featured },
      ]"
      :style="{ '--accent': options.accentColor }"
    >
      <span v-if="options.badge" class="pricing-card__badge">
        {{ options.badge }}
      </span>
      <h3>{{ title }}</h3>
      <p class="pricing-card__price">{{ price }}</p>
      <ul>
        <li v-for="feature in features" :key="feature">{{ feature }}</li>
      </ul>
    </div>
  </template>

  <script lang="ts" setup>
  defineProps<{
    title: string
    price: string
    features: string[]
  }>()

  const { options } = defineBlokkli({
    bundle: 'pricing_card',
    options: {
      style: {
        type: 'radios',
        label: 'Card style',
        group: 'Appearance',
        default: 'outline',
        options: { outline: 'Outline', filled: 'Filled', minimal: 'Minimal' },
      },
      accentColor: {
        type: 'color',
        label: 'Accent color',
        group: 'Appearance',
        default: '#6366f1',
      },
      featured: {
        type: 'checkbox',
        label: 'Featured card',
        group: 'Appearance',
        default: false,
      },
      badge: {
        type: 'text',
        label: 'Badge label',
        group: 'Content',
        default: '',
      },
    },
  })
  </script>
  ```

  ```typescript Options Only theme={null}
  {
    style: {
      type: 'radios',
      label: 'Card style',
      group: 'Appearance',
      default: 'outline',
      options: { outline: 'Outline', filled: 'Filled', minimal: 'Minimal' },
    },
    accentColor: {
      type: 'color',
      label: 'Accent color',
      group: 'Appearance',
      default: '#6366f1',
    },
    featured: {
      type: 'checkbox',
      label: 'Featured card',
      group: 'Appearance',
      default: false,
    },
    badge: {
      type: 'text',
      label: 'Badge label',
      group: 'Content',
      default: '',
    },
  }
  ```
</CodeGroup>
