Was this page helpful?

UI Extensions SDK reference

This document describes the SDK that a custom extension can use to communicate with the Contentful Web App and the Contentful Management API.

Table of Contents

Usage

Methods

Inclusion in your project

You will need to include the contentful-ui-extensions-sdk library in your HTML5 app:

<script src="https://unpkg.com/contentful-ui-extensions-sdk@3"></script>

The SDK is also distributed as an NPM package.

npm install --save contentful-ui-extensions-sdk

Initialization

The SDK exposes the contentfulExtension.init() method. This is the entry point for all extension-related code. If you require the script from the CDN and use it without any module system the init method is available as window.contentfulExtension.init:

window.contentfulExtension.init(function(extension) {
  var value = extension.field.getValue()
  extension.field.setValue("Hello world!")
})

If you use a bundler supporting ES6 modules you can use the import statement:

import { init as initContentfulExtension } from "contentful-ui-extensions-sdk"

initContentfulExtension(extension => {
  /* ... */
})

If you use a CommonJS bundler you need to require the Extensions SDK:

const contentfulExtension = require("contentful-ui-extensions-sdk")

contentfulExtension.init(extension => {
  /* ... */
})

Locations

Currently UI Extensions can be rendered in 4 places. All available locations are exported as constants:

import { init, locations } from "contentful-ui-extensions-sdk"
  • locations.LOCATION_ENTRY_FIELD - extension is rendered as a content field control; the API has all the methods available.
  • locations.LOCATION_ENTRY_SIDEBAR - extension is rendered in the entry sidebar; field API methods are not available.
  • locations.LOCATION_ENTRY_EDITOR - extension replaces the default entry editor; field and window API methods are not available.
  • locations.LOCATION_DIALOG - extension is rendered in its own dialog. field and entry API methods are not available.

Deprecated:

  • locations.LOCATION_ENTRY_FIELD_SIDEBAR - extension is rendered as a content field control, but in the sidebar; all methods available. Use locations.LOCATION_ENTRY_SIDEBAR instead.

To check the location in which your extension is running use location.is:

import { init, locations } from "contentful-ui-extensions-sdk"

init(api => {
  if (api.location.is(locations.LOCATION_ENTRY_SIDEBAR)) {
    renderSidebarUI()
  }
  if (api.location.is(locations.LOCATION_DIALOG)) {
    renderDialogUI()
  }
})

Since 3.6.0

Field

extension.field

This API gives you access to the value and metadata of the field the extension is attached to.

If you use localization, an extension instance will be rendered for each locale. This means you can only change the value for the given locale. See the entry.fields API for how to change values for different locales.

If an entry returned by the Contentful Management API looks like the following:

{
  sys: { ... },
  fields: {
    title: {
      "en_US": "My Post"
    },
    ...
  }
}

Then the extension is attached to the title field and the en_US locale.

Getting field values

extension.field.getValue(): mixed

Gets the current value of the field and locale. In the example this would yield "My Post".

Setting field values

extension.field.setValue(value): Promise<mixed>

Sets the value for the field and locale. The promise is resolved when the change has been acknowledged. The type of the value must match the expected field type. For example, if the extension is attached to a "Symbol" field you must pass a string.

Example:

extension.field
  .setValue("foo")
  .then(data => {
    console.log(data) // Returns "foo".
  })
  .catch(err => {
    console.log(err)
  })

Removing field values

extension.field.removeValue(): Promise<void>

Removes the value for the field and locale. A subsequent call to getValue() for the field would yield undefined.

Setting a field to be invalid/valid

extension.field.setInvalid(Boolean): undefined

Communicates to the Contentful web application if the field is in a valid state or not. This impacts the styling applied to the field container.

Receiving notifications for external field value changes

extension.field.onValueChanged(callback): function

Calls the callback every time the value of the field is changed by an external event (e.g. when multiple editors are working on the same entry) or when setValue() is called.

The method returns a function you can call to stop listening to changes.

Example:

// Handler for external field value changes.
function valueChangeHandler(value) {
  inputEl.value = value || ""
}
// Callback for changes of the field value.
var detachValueChangeHandler = extension.field.onValueChanged(
  valueChangeHandler
)

Use detachValueChangeHandler() to unsubscribe.

Changed in v3.0.0

Receiving notifications for external enabling/disabling of field

extension.field.onIsDisabledChanged(callback): function

Calls the callback when the disabled status of the field changes. A boolean indicating whether the field is disabled or not is passed to the callback.

The method returns a function that you can call to stop listening to changes.

See above for an example.

Receiving notifications when field is re-validated

extension.field.onSchemaErrorsChanged(callback): function

Calls the callback immediately with the current validation errors and whenever the field is re-validated. The callback receives an array of error objects. An empty array indicates no errors.

The errors are updated when the app validates an entry. This happens when loading an entry or when the user tries to publish it.

The method returns a function that you can call to stop listening to changes.

See above for an example.

Since v2.1.0

Getting the id of the field

extension.field.id: string

The ID of a field is defined in an entry's content type. Yields "title" in the example.

Getting the locale of the field

extension.field.locale: string

The current locale of a field the extension is attached to. Yields "en_US" in the example.

Getting the type of the field

extension.field.type: string

Holds the type of the field the extension is attached to. The field type can be one of those described in our api documentation.

Getting the validations of the field

extension.field.validations: Validation[]

A list of validations for this field that are defined in the content type. The content type documentation provides more information on the shape of validations.

Since v2.1.0

Entry

extension.entry

This object allows you to read and update the value of any field of the current entry and to get the entry's metadata.

Getting the Entry's sys object

entry.getSys(): object

Returns metadata for an entry. The value coincides with the sys value of an entry returned by the v0.8.x of the Contentful Management API.

Receiving notifications when sys object is changing

entry.onSysChanged(callback): function

Calls the callback with metadata every time that metadata changes. You can call the returned function to stop listening to changes.

See above for an example.

Getting individual fields of an Entry

entry.fields[id]: Field

In addition to extension.field, a extension can also control the values of all other fields in the current entry. Fields are referenced by their ID.

The Field API methods provide a similar interface to extension.field. The methods also accept an optional locale to change the value for a specific locale. It defaults to the space the space's default locale (see extension.locales). Providing an unknown locale throws an exception.

  • field.id: string
  • field.locales: Array<string>
  • field.getValue(locale?): mixed
  • field.setValue(value, locale?): Promise<void>
  • field.removeValue(locale?): Promise<void>
  • field.onValueChanged(locale?, cb): function
  • field.onIsDisabledChanged(locale?, cb): function

Example: If the entry has a "title" field, you can transform it to upper case with:

var titleField = extension.entry.fields.title
var oldTitle = titleField.getValue()
titleField.setValue(oldTitle.toUpperCase())

Content Type

extension.contentType

This API gives you access to data about the content type of the entry. It has the form as described under "content type properties" in our api documentation.

Since 1.0.0

The object it returns looks similar to this:

{
  sys: { ... },
  fields: { ... },
  name: "fooContentType",
  displayField: "title",
  description: "This is an example description of a Content Type"
}

Space

extension.space

The space object exposes methods that allow the extension to read and manipulate a wide range of objects in the space. Its API mirrors v0.8.x of the contentful-management library, with a few differences.

Content Types of a Space

Allows operating on the current space's content types. Content types created/updated or deleted this way will immediately be published or unpublished respectively.

  • space.getContentType(id)
  • space.getContentTypes()
  • space.createContentType(data)
  • space.updateContentType(data)
  • space.deleteContentType(data)

Entries of a Space

  • space.getEntry(id)
  • space.getEntrySnapshots(id)
  • space.getEntries(query)
  • space.createEntry('content-type-id', data)
  • space.updateEntry(data)
  • space.publishEntry(data)
  • space.unpublishEntry(data)
  • space.archiveEntry(data)
  • space.unarchiveEntry(data)
  • space.deleteEntry(data)
  • space.getPublishedEntries(query)

Since 1.0.0 getEntrySnapshots since 3.6.0

Assets of a Space

  • space.archiveAsset(data)
  • space.createAsset(data)
  • space.createUpload(base64data)
  • space.deleteAsset(data)
  • space.getAsset(id)
  • space.getAssets(query)
  • space.getPublishedAssets(query)
  • space.processAsset(asset, locale)
  • space.publishAsset(data)
  • space.unarchiveAsset(data)
  • space.unpublishAsset(data)
  • space.updateAsset(data)
  • space.waitUntilAssetProcessed(assetId, locale)

Note that snapshots are not available for assets.

Since 1.0.0 createUpload and waitUntilAssetProcessed since 3.7.0

Editor Interface

space.getEditorInterface()

since 3.8.0

Users of a Space

space.getUsers()

Returns a promise of all User objects for users who belong to the Space.

Since 3.6.0

Locales

extension.locales

A space can have multiple locales and each localized entry field can have different values for different locales. Locales are identified by their locale code, e.g. "en_US".

Default Locale

locales.default: string

The default locale code for the current space.

Listing Locales

locales.available: Array<string>

A list of locale codes of all locales available for editing in the current space.

Locale names

locales.names: Object

An object with keys of locale codes and values of corresponding human-readable locale names.

{
  available: ['en-US', 'pl'],
  default: 'en-US',
  names: {
    'en-US': 'English (US)',
    pl: 'Polski'
  }
}

Since 3.4.3

User

extension.user

This object holds information about the current user and roles. It has the following shape.

{
  sys: { id: 'b33ts', type: 'User' },
  firstName: 'Dwight',
  lastName: 'Schrute',
  email: 'dwight@dundermifflin.com',
  avatarUrl: 'https://avatar.com/x.jpg',
  spaceMembership: {
    sys: { id: 'abc123xyz', type: 'SpaceMembership' }
    admin: false,
    roles: [{
      name: 'Assistant to the regional manager',
      description: 'Not “Assistant regional manager”',
    }]
  }
}

The spaceMembership and roles objects have include a subset of the data from the corresponding resources in the Contentful Management API. You can find more information in the CMA Reference Documentation.

Since v3.3.0

Window

extension.window

The window object provides methods to update the size of the iframe the extension is contained within. This prevents scrollbars inside the extension.

To prevent a flickering scrollbar during height updates, it is recommended to set the extension's body to overflow: hidden;.

Updating the extension's height

window.updateHeight()

Calculates the body's scrollHeight and sets the containers height to this value.

Setting the extension's height

window.updateHeight(height)

Sets the iframe height to the given value in pixels. height must be an integer.

Automatically updating the extension's height

window.startAutoResizer()

Listens for DOM changes and calls updateHeight() when the size changes.

Stopping the automatic updating of the extension's height

window.stopAutoResizer()

Stops resizing the iframe automatically.

Dialogs

extension.dialogs

This object provides methods for opening UI dialogs:

Opening an extension in a dialog

dialogs.openExtension(options)

Opens an extension in a dialog.

options is an object configuring the dialog. The available options are:

  • id (string, required): ID of the extension to open.
  • width (number): width of the dialog in pixels. Defaults to 700.
  • position (center | top): vertical position of the dialog. Defaults to center.
  • title (string): adds header to the dialog if specified
  • shouldCloseOnOverlayClick (boolean): indicates if clicking the overlay should close the dialog. Defaults to false.
  • shouldCloseOnEscapePress (boolean): indicates if pressing the ESC key should close the dialog. Defaults to false.
  • parameters (mixed): invocation parameters to pass to the extension. Can be accessed as parameters.invocation in the opened extension.

openExtension returns a promise. Inside the extension opened in a dialog you can call close(data) which will close the dialog and resolve the promise with data.

// Extension to open: `mydialog`.
init(api => {
  console.log(api.parameters.invocation)
  api.close({ hello: "world" })
})

// Opening the extension:
dialogs
  .openExtension({
    id: "mydialog",
    width: 500,
    parameters: { test: true, value: 42 }
  })
  .then(data => {
    /* ... */
  })

Since 3.6.0

Opening an alert dialog

dialogs.openAlert(options)

Opens a simple alert window (which can only be closed). The method returns a promise always resolving to true once the dialog is closed.

options is an object configuring the dialog. The available options are:

  • title (string, required): title of the dialog.
  • message (string, required): message of the dialog.
  • confirmLabel (string, optional): label of the confirmation button. Defaults to "Confirm".
  • shouldCloseOnEscapePress (boolean, optional): indicates if pressing the Escape key closes the dialog. Defaults to true.
  • shouldCloseOnOverlayClick (boolean, optional): indicates if clicking the dialog overlay closes the dialog. Defaults to true.
dialogs
  .openAlert({
    title: "My alert",
    message: "My message to you"
  })
  .then(result => {
    // `result` is always `true`, can be skipped
  })

Since v3.4.2

Opening a confirm dialog

dialogs.openConfirm(options)

Opens a confirmation window. A user can either confirm or cancel the dialog. The method returns a promise resolving to either true (for confirmations) or false (for cancellations). Clicking the dialog overlay or pressing the Escape key (if enabled) will cancel the dialog.

options is an object configuring the dialog. The available options are the options of dialogs.openAlert(options) and additionally:

  • cancelLabel (string, optional): label of the cancellation button. Defaults to "Cancel".
  • intent (primary, positive, negative): color of the confirmation button. Defaults to primary.
dialogs
  .openConfirm({
    title: "My question",
    message: "What is your answer?",
    intent: "positive",
    confirmLabel: "Yes!",
    cancelLabel: "No..."
  })
  .then(result => {
    // `result` is either `true` or `false`
  })

Since v3.4.2

Opening a prompt dialog

dialogs.openPrompt(options)

Opens a prompt window. A user can either provide a string input or cancel the dialog. The method returns a promise resolving the provided string (when confirmed) or false (when cancelled). Clicking the dialog overlay or pressing the Escape key (if enabled) will cancel the dialog.

options is an object configuring the dialog. The available options are the options of dialogs.openConfirm(options) and additionally:

  • defaultValue (string, optional): the default value of the text input. Defaults to an empty string.
dialogs
  .openPrompt({
    title: "My question",
    message: "Please tell me more...",
    defaultValue: "hello world"
  })
  .then(result => {
    // `result` is either a string or `false`
  })

Since v3.4.2

Selecting a single Entry

dialogs.selectSingleEntry(options)

Opens a dialog for selecting a single entry. It returns a promise resolved with the selected entity or null if a user closes the dialog without selecting anything.

options is an optional object configuring the dialog.The available options are:

  • locale: The code of a locale you want to use to display proper titles and descriptions. Defaults to the space's default locale.
  • contentTypes: An array of content type IDs of entries that you want to display in the selector. By default entries of all content types are displayed.
// display a dialog for selecting a single entry
dialogs.selectSingleEntry().then(selectedEntry => {})

// select a single entry of "blogpost" content type
// and display result in "de-DE" locale
dialogs
  .selectSingleEntry({
    locale: "de-DE",
    contentTypes: ["blogpost"]
  })
  .then(selectedEntry => {})

Since v3.1.0

Selecting multiple Entries

dialogs.selectMultipleEntries(options)

Works similarly to selectSingleEntry, but allows to select multiple entries and the returned promise is resolved with an array of selected entries.

Both locale and contentTypes options can be used. There are two additional options:

  • min and max - numeric values specifying an inclusive range in which the number of selected entities must be contained
// display a dialog for selecting multiple entries
dialogs.selectMultipleEntries().then(arrayOfSelectedEntries => {})

// select between 1 and 3 (inclusive) entries
dialogs
  .selectMultipleEntries({ min: 1, max: 3 })
  .then(arrayOfSelectedEntries => {})

Since v3.1.0

Selecting a single Asset

dialogs.selectSingleAsset(options)

Counterpart of selectSingleEntry for assets. A contentTypes option is not available.

Since v3.1.0

Selecting multiple Assets

dialogs.selectMultipleAssets(options)

Counterpart of selectMultipleEntries for assets. A contentTypes option is not available.

Since v3.1.0

extension.navigator

Exposes methods for navigating between entities stored in a Contentful space.

Opening an existing entry or asset

  • navigator.openEntry(entryId, options)
  • navigator.openAsset(assetId, options)

Opens an existing entry or asset in the current Web App session. Both entryId and assetId are string identifiers as in the sys.id property of an entity.

options object is optional. The only recognized option is { slideIn: true }. When set, it will open the entity in the slide-in editor over the current entity editor instead of navigating.

navigator.openAsset("si29ajxns80", { slideIn: true }).then(({ entity }) => {
  /* asset was opened in the slide-in editor */
})

Since v3.5.0

Opening a new entry or asset

  • navigator.openNewEntry(contentTypeId, options)
  • navigator.openNewAsset(options)

Opens a new entry or asset in the current Web App session. When opening an entry, contentTypeId string identifier must be provided. options object is optional and has the same effect as in openEntry and openAsset methods.

navigator.openNewEntry("blogPost", { slideIn: true }).then(({ entity }) => {
  /* new entry of the "blogPost" content type was opened in the slide-in editor */
})

Since v3.5.0

Notifier

extension.notifier

Allows to display notifications.

Displaying success and error notifications

  • notifier.success(message)
  • notifier.error(message)

Provided with a string message, displays a success (rendered in green) or an error (rendered in red) notification in the notification area of the Web App.

notifier.success("Settings successfully updated!")

Since v3.5.0

Editor

extension.editor

Exposes editor interface and provides subscription methods for editor state: locale mode, selected locales, visibility of fields disabled for editing.

Editor Interface

  • editor.editorInterface - instance of EditorInterface entity for the content type of the entry being edited

Receiving notifications about locales settings change

extension.editor.onLocaleSettingsChanged(callback): function

Calls the callback every time locale mode (single or multi), active locales or focused locale are changed.

The method returns a function you can call to stop listening to changes.

Example:

function localeSettingsHandler(data) {
  const { mode, focused, active } = data
  if (mode === "single") {
    console.log(focused)
  } else if (mode === "multi") {
    console.log(active)
  }
}
const detachHandler = extension.editor.onLocaleSettingsChanged(
  localeSettingsHandler
)
  • active locales: array of locales codes, present in multi mode
  • focused locale: currently focused locale code, present in single mode

Use detachHandler() to unsubscribe.

Receiving notifications about changes of visibility of fields disabled for editing

extension.editor.onShowDisabledFieldsChanged(callback): function

Calls the callback every time disabled fields visibility is changed.

The method returns a function you can call to stop listening to changes.

Example:

function visibilityHandler(visible) {
  if (visible) {
    console.log("show disabled fields")
  } else {
    console.log("hide disabled fields")
  }
}
const detachHandler = extension.editor.onShowDisabledFieldsChanged(
  visibilityHandler
)

Use detachHandler() to unsubscribe.

Since v3.8.0

IDs

Exposes IDs of entities available in the current context.

  • user - ID of the current user
  • extension - ID of the current extension
  • space - ID of the current space
  • environment - ID of the current space
  • entry - ID of the current entry
  • contentType - ID of the current content type
  • field - ID of the current field

Since v3.8.0

Configuration of an extension with parameters

extension.parameters

Exposes extension configuration parameters as defined in the Content Management API reference.

extension.parameters has the following shape:

{
  installation: {
    retries: 10,
    isDevMode: true
  },
  instance: {
    theme: 'light'
  }
}

You can rely on both extension.parameters.installation and extension.parameters.instance being defined. If no parameters were provided they will default to an empty object:

{
  installation: {},
  instance: {}
}

Since v3.4.0

If your extension was opened with dialogs.openExtension, you can access invocation parameters as parameters.invocation. Invocation parameters are not guaranteed to be defined and depend on the extension type and value provided when opening a dialog.

Since 3.6.0