Skip to main content
Your adapter must implement these seven methods for a minimal working editor. Without them, blökkli cannot load content, display available block types, or handle user actions. All seven must be present and return the expected shapes — blökkli will throw a runtime error if any are missing when the editor activates.
All methods are async and must return a Promise. You can use async/await or return a Promise directly — both are fully supported.

loadState()

Fetches the raw initial content for the entity being edited. blökkli calls this method once, immediately after the editor overlay activates. The return value is passed directly to mapState() as its state argument. You have full control over the return shape — mapState() is responsible for the transformation. Signature
async loadState(): Promise<any>
Example
async loadState() {
  return $fetch(`/api/content/${ctx.state.value.currentEntityUuid}`)
}
Return the full API response here rather than pre-processing it. Keep all transformation logic in mapState() so both methods stay focused on a single responsibility.

mapState(state)

Transforms the raw value returned by loadState() into blökkli’s expected internal format. blökkli calls this immediately after loadState() and whenever it needs to reconcile state (for example, after an undo/redo operation). Your return value must include at minimum a blocks array. Signature
async mapState(state: any): Promise<MappedState>
Example
async mapState(state: any): Promise<MappedState> {
  return {
    blocks: state.data.paragraphs.map((p: any) => ({
      uuid: p.id,
      bundle: p.type,
      hostField: p.field,
      ...p.attributes,
    })),
  }
}
MappedState is exported from @blokkli/editor. Each block object in the blocks array must include uuid (string), bundle (string), and hostField (string) at minimum. Additional properties are passed as props to your block components.

getAllBundles()

Returns the list of block types the current user can add. blökkli calls this once on editor activation and uses the result to populate the “Add block” panel. Each bundle object requires at least an id and a label. Signature
async getAllBundles(): Promise<BundleDefinition[]>
Example
async getAllBundles(): Promise<BundleDefinition[]> {
  return [
    { id: 'text',  label: 'Text Block'     },
    { id: 'image', label: 'Image'          },
    { id: 'hero',  label: 'Hero Banner'    },
    { id: 'cta',   label: 'Call to Action' },
  ]
}
You can filter the returned bundles based on the current user’s permissions by reading ctx.state.value inside the method. Return only the bundles the user is allowed to create.

getFieldConfig()

Returns configuration for each block field (region) in the current entity, including which block types are allowed in each region. blökkli uses this to validate drag-and-drop targets and to enforce allowed block types. Signature
async getFieldConfig(): Promise<FieldConfig[]>
Example
async getFieldConfig(): Promise<FieldConfig[]> {
  return [
    {
      name:           'blocks',
      label:          'Page Content',
      allowedBundles: ['text', 'image', 'hero', 'cta'],
      entityType:     'node',
      entityBundle:   'page',
    },
  ]
}
The name value in each FieldConfig entry must match the name prop on the corresponding <BlokkliField> component in your template. Mismatches cause the field to behave as if it has no allowed bundles.

addNewBlock(options)

Persists a newly added block to your backend. blökkli calls this when the user drags a block type from the add-block panel, or clicks a block type to insert it at the current cursor position. Signature
async addNewBlock(options: AddNewBlockOptions): Promise<void>
bundle
string
required
The block type identifier to create (matches an id from getAllBundles()).
hostField
string
required
The field name of the target region (matches a name from getFieldConfig()).
preceedingUuid
string | null
required
UUID of the block that the new block should be placed after. null means insert at the beginning of the field.
options
Record<string, any>
Initial option values for the new block, if any defaults were configured.
Example
async addNewBlock({
  bundle,
  hostField,
  preceedingUuid,
  options,
}: AddNewBlockOptions): Promise<void> {
  await $fetch('/api/blocks', {
    method: 'POST',
    body: { bundle, hostField, preceedingUuid, options },
  })
}

moveBlock(options)

Persists the new position of a single block after the user drags it to a different location. blökkli updates its internal state optimistically and calls this method to sync the change to your backend. Signature
async moveBlock(options: MoveBlockOptions): Promise<void>
uuid
string
required
UUID of the block being moved.
hostField
string
required
The target field name. May differ from the block’s current field if the user moves it across regions.
preceedingUuid
string | null
required
UUID of the block that should precede the moved block in its new position. null places it at the start of the field.
Example
async moveBlock({
  uuid,
  hostField,
  preceedingUuid,
}: MoveBlockOptions): Promise<void> {
  await $fetch(`/api/blocks/${uuid}/move`, {
    method: 'PATCH',
    body: { hostField, preceedingUuid },
  })
}

moveMultipleBlocks(options)

Persists the new positions of multiple blocks simultaneously. blökkli calls this when the user has selected more than one block and drags the selection to a new position. Signature
async moveMultipleBlocks(options: MoveMultipleBlocksOptions): Promise<void>
uuids
string[]
required
Ordered array of UUIDs for the blocks being moved. The order reflects the blocks’ relative sequence after the move.
hostField
string
required
The target field name for all moved blocks.
preceedingUuid
string | null
required
UUID of the block that the moved group should be placed after. null places the group at the start of the field.
Example
async moveMultipleBlocks({
  uuids,
  hostField,
  preceedingUuid,
}: MoveMultipleBlocksOptions): Promise<void> {
  await $fetch('/api/blocks/move-multiple', {
    method: 'PATCH',
    body: { uuids, hostField, preceedingUuid },
  })
}
Your backend must handle the ordering implied by uuids correctly. The array is already in the final desired order — persist it in that sequence.