---
url: /cookbook/custom-input-types-legacy.md
description: >-
  Deprecated pre-3.28 patterns for implementing custom WPCE input types with the
  Vue Options API and AbstractInputComponent.
---

# Custom Input Types (Legacy)&#x20;

:::warning
This page describes some functionality of custom input types as they were used prior to WPCE . To not have this information clutter the [documentation of the current system](../documentation/concepts/input-types), they have been moved here.

Note that while all of the approaches described here are still supported, they are not recommended to be used in new projects.
:::

Since WPCE 3.5, input types are no longer a fixed entity defined by the WPCE plugin itself. While the input types documented on this site are still available, they are now registered through an interface that is accessible from the outside as well.

## What is a Custom Input Type?

At its core, a custom input type is just a Vue component.

The baseline requirement is for this component to expose two methods:

* `getValue()`: Returns the current value of the input
* `isValid()`: Returns `true` if the input is currently in a valid state, `throw`s an error message string otherwise; may be asynchronous (since )

The component can also expose an optional `isDirty()` method to report whether its contents have changed.

## Implementation (Composition API)&#x20;

Context data about the input type can be received through the `useInputType()` composable, exposed on the global [instance manager](../documentation/concepts/glossary#instance-manager)'s `inputTypeUtils` property:

```js
const { useInputType } = window.wpce.inputTypeUtils
const { node, property, value } = useInputType()

// `node` refers to the document node being edited
// `property` refers to the definition of the property which has the input type assigned
// `value` is the pre-existing value
```

As an example, here's a custom input type component that works as a fully compatible drop-in replacement for the `select` input type, but using radio buttons instead:

```vue
<script setup>
import { ref } from 'vue'

const { property, value } = window.wpce.inputTypeUtils.useInputType()

const newValue = ref(value ?? property.input.options[0].value)
const name = `wpce-radio-${crypto.randomUUID()}`

defineExpose({
  getValue: () => newValue.value,
  isValid: () => true
})
</script>

<template>
  <label v-for="{ value, label } of property.input.options">
    <input type="radio" v-bind="{ name, value }" v-model="newValue" />
    {{ label }}
  </label>
</template>

<style lang="scss" scoped>
label {
  display: block;

  input {
    width: auto !important;
  }
}
</style>
```

## Implementation (Options API)

Up until WPCE , the `useInputType()` composable was not available and custom input types were preferrably implemented by extending the `AbstractInputComponent`. As an equivalent to the above `radio` input type, this would have been the way to implement it before WPCE 3.14:

```vue
<template>
  <label v-for="{ value, label } of prop.input.options">
    <input type="radio" v-bind="{ name, value }" v-model="internalValue" />
    {{ label }}
  </label>
</template>

<script>
export default {
  extends: window.wpce.AbstractInputComponent,
  data() {
    return {
      internalValue: this.value ?? this.prop.input.options[0].value,
      name: `wpce-radio-${crypto.randomUUID()}`
    }
  },
  methods: {
    getValue() {
      return this.internalValue
    },
    isValid: () => true
  }
}
</script>

<style lang="scss" scoped>
label {
  display: block;

  input {
    width: auto !important;
  }
}
</style>
```

## Registering the Input Type

The registration interface is accessible through the WPCE instance's `registerInputType` method, so it should be used during the `wpce_instance_added` event:

```js
import RadioInput from './RadioInput.vue'

document.addEventListener('wpce_instance_added', function (event) {
  const editor = event.detail.instance

  editor.registerInputType('radio', RadioInput)
})
```

As can be seen in the example above, the `registerInputType` takes the input type's identifier (as used in element definitions) as its first parameter and the according component second.

### Additional Options&#x20;

An optional third parameter can be used to pass an object with options for the input type.

***

#### `layout`

How the label/description and the interactive part of the input type should be arranged in a property form.

`'auto'` (the default) uses built-in heuristics for dispay, usually arranging it as a `row`.

**Type:**

```ts
'row' | 'column' | 'auto' | 'custom'
```
