Single-Select Field

Store one choice from a predefined option list on a record — for status, priority, category, or any controlled single-choice value.


A single-select field stores exactly one option chosen from a predefined list. Use it for status, priority, category, or any value that must come from a controlled set where only one choice is valid at a time. In the API this is a CustomField with type: SELECT_SINGLE; selectable options are CustomFieldOption objects, and the chosen option for a given record is exposed as selectedOption.

Custom fields are scoped to a workspace (a Workspace), set with the X-Bloo-Project-ID header. Records are Record objects.

Overview

A single-select field is created in two steps: create the field, then add its options. The field on its own holds no choices — the options you attach to it are what users (and the API) can select.

AspectSingle-Select
CustomFieldType valueSELECT_SINGLE
Selection limitOne option
Set value withcustomFieldOptionId (or customFieldOptionIds, first element only)
Reads back asselectedOption (a single CustomFieldOption)

Create

Create the field with createCustomField. There is no inline option list — options are added separately after the field exists.

mutation CreateSingleSelectField {
  createCustomField(input: { name: "Priority", type: SELECT_SINGLE }) {
    id
    name
    type
  }
}

Then add options to that field with createCustomFieldOptions. The customFieldId is passed once on the wrapper input; each entry in customFieldOptions carries only its own properties.

mutation AddPriorityOptions {
  createCustomFieldOptions(
    input: {
      customFieldId: "field_123"
      customFieldOptions: [
        { title: "Low", color: "#28a745" }
        { title: "Medium", color: "#ffc107" }
        { title: "High", color: "#fd7e14" }
        { title: "Critical", color: "#dc3545" }
      ]
    }
  ) {
    id
    title
    color
    position
  }
}

To add a single option to an existing field, use createCustomFieldOption instead, which takes customFieldId directly on its input.

mutation AddOneOption {
  createCustomFieldOption(
    input: { customFieldId: "field_123", title: "Urgent", color: "#6f42c1" }
  ) {
    id
    title
    color
    position
  }
}

CreateCustomFieldInput

ParameterTypeRequiredDescription
nameString!YesDisplay name of the field.
typeCustomFieldType!YesMust be SELECT_SINGLE.
descriptionStringNoHelp text shown to users.

CreateCustomFieldOptionsInput

ParameterTypeRequiredDescription
customFieldIdString!YesThe single-select field the options belong to.
customFieldOptions[CustomFieldOptionInput!]!YesThe options to create.

CustomFieldOptionInput

ParameterTypeRequiredDescription
titleString!YesDisplay text for the option.
colorStringNoColor for the option (any string; the app uses hex).
positionFloatNoSort order. Defaults to append order when omitted.

Set a value

Set the selected option on a record with setRecordCustomField, passing the chosen option’s id as customFieldOptionId. Setting a new option replaces any previous selection. setRecordCustomField returns Boolean! — select no subfields on it.

mutation SetPriority {
  setRecordCustomField(
    input: { todoId: "todo_123", customFieldId: "field_123", customFieldOptionId: "option_123" }
  )
}
{ "data": { "setRecordCustomField": true } }

You can also create a record with the value already set. In createRecord, the option id is passed as the string value (not a separate option-id field).

mutation CreateRecordWithPriority {
  createRecord(
    input: {
      title: "Review onboarding flow"
      todoListId: "list_123"
      customFields: [{ customFieldId: "field_123", value: "option_123" }]
    }
  ) {
    id
    title
  }
}

SetRecordCustomFieldInput

ParameterTypeRequiredDescription
todoIdString!YesThe record to update.
customFieldIdString!YesThe single-select field.
customFieldOptionIdStringNoThe option to select. Preferred for single-select.
customFieldOptionIds[String!]NoAccepted for parity with multi-select; only the first element is used.
Only one id is kept

If you pass customFieldOptionIds to a SELECT_SINGLE field, the resolver keeps only the first id and ignores the rest. To clear the selection, call setRecordCustomField with neither customFieldOptionId nor customFieldOptionIds.

Read a value

A record’s custom field values come back on Record.customFields, which returns [CustomField!]! directly. For a single-select field, read the chosen option from selectedOption. There is no wrapper type — select option fields straight off the element.

query GetRecordPriority {
  recordQueries {
    todos(filter: { companyIds: ["company_123"], todoIds: ["todo_123"] }) {
      items {
        id
        title
        customFields {
          id
          name
          type
          selectedOption {
            id
            title
            color
          }
        }
      }
    }
  }
}
{
  "data": {
    "recordQueries": {
      "todos": {
        "items": [
          {
            "id": "clm4n8qwx000008l0g4oxdqn7",
            "title": "Review onboarding flow",
            "customFields": [
              {
                "id": "clm4n8field0000priority01",
                "name": "Priority",
                "type": "SELECT_SINGLE",
                "selectedOption": {
                  "id": "clm4n8opt0000highprio0001",
                  "title": "High",
                  "color": "#fd7e14"
                }
              }
            ]
          }
        ]
      }
    }
  }
}

CustomField.value also returns a JSON representation of the selection, but selectedOption is the typed, schema-checked path and the one to prefer.

Returns

CustomField fields relevant to a single-select field:

FieldTypeDescription
idID!The field id.
nameString!Display name.
typeCustomFieldType!SELECT_SINGLE.
customFieldOptions[CustomFieldOption!]All options defined on the field.
selectedOptionCustomFieldOptionThe option chosen on this record, or null.

CustomFieldOption fields:

FieldTypeDescription
idID!The option id.
titleString!Display text.
colorString!The option color.
positionFloat!Sort order within the field.

Manage options

Edit an option with editCustomFieldOption, identifying it by customFieldId plus optionId (not a single id). It returns the updated CustomFieldOption.

mutation RenameOption {
  editCustomFieldOption(
    input: {
      customFieldId: "field_123"
      optionId: "option_123"
      title: "Top Priority"
      color: "#ff6b6b"
    }
  ) {
    id
    title
    color
  }
}

Reorder options by setting position — there is no separate reorder mutation. Use a value between two existing positions to slot an option in.

mutation MoveOption {
  editCustomFieldOption(
    input: { customFieldId: "field_123", optionId: "option_123", position: 1.5 }
  ) {
    id
    position
  }
}

Delete an option with deleteCustomFieldOption, which takes customFieldId and optionId and returns Boolean!. Deleting an option clears it from every record where it was selected.

mutation RemoveOption {
  deleteCustomFieldOption(customFieldId: "field_123", optionId: "option_123")
}
{ "data": { "deleteCustomFieldOption": true } }

EditCustomFieldOptionInput

ParameterTypeRequiredDescription
customFieldIdString!YesThe field the option belongs to.
optionIdString!YesThe option to edit.
titleStringNoNew display text.
colorStringNoNew color.
positionFloatNoNew sort order.

Notes

  • Setting a new option replaces the previous one — single-select selections are not additive.
  • Options live on the field, not the record, so they are shared by every record that uses the field.
  • color on a created option is stored as a string; the app renders hex values, but no hex validation is enforced.

Errors

CodeWhen
CUSTOM_FIELD_NOT_FOUNDThe customFieldId does not resolve to a field in the current workspace.
CUSTOM_FIELD_OPTION_NOT_FOUNDThe option id does not exist, or does not belong to the given field.
TODO_NOT_FOUNDThe todoId does not resolve to a record.
CUSTOM_FIELD_VALUE_PARSE_ERRORThe supplied value cannot be parsed for this field type.
FORBIDDENThe caller lacks permission to modify the field or set the value.