# Attributes

The API for interacting with cart and checkout attributes.

```jsx
import {
  Text,
  reactExtension,
  useAttributeValues,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
  'purchase.checkout.block.render',
  () => <Extension />,
);

function Extension() {
  const [buyerSelectedFreeTShirt, tshirtSize] =
    useAttributeValues([
      'buyerSelectedFreeTShirt',
      'tshirtSize',
    ]);

  if (Boolean(buyerSelectedFreeTShirt) === true) {
    return (
      <Text>
        You selected a free t-shirt, size:{' '}
        {tshirtSize}
      </Text>
    );
  }

  return null;
}

```

```js
import {
  extension,
  Text,
} from '@shopify/ui-extensions/checkout';

export default extension(
  'purchase.checkout.block.render',
  (root, {attributes}) => {
    attributes.subscribe(() => {
      renderUI();
    });

    function renderUI() {
      const buyerSelectedFreeTShirt =
        attributes.current?.find(
          (attr) =>
            attr.key ===
            'buyerSelectedFreeTShirt',
        )?.value;

      const tshirtSize = attributes.current?.find(
        (attr) => attr.key === 'tshirtSize',
      )?.value;

      if (
        Boolean(buyerSelectedFreeTShirt) === true
      ) {
        root.replaceChildren(
          root.createComponent(
            Text,
            undefined,
            `You selected a free t-shirt, size: ${tshirtSize}`,
          ),
        );
      } else {
        root.replaceChildren();
      }
    }

    renderUI();
  },
);

```

## StandardApi

The base API object provided to `purchase` extension targets.

### Docs_Standard_AttributesApi

### attributes

value: `StatefulRemoteSubscribable<Attribute[] | undefined>`

The custom attributes left by the customer to the merchant, either in their cart or during checkout.

### Attribute

### key

value: `string`

The key for the attribute.

### value

value: `string`

The value for the attribute.

## Related

- [Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets)
- [Components](https://shopify.dev/docs/api/checkout-ui-extensions/components)
- [Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration)
- [Tutorials](/apps/checkout)

## Examples

The API for interacting with cart and checkout attributes.


You can add or remove cart and checkout attributes by using the `applyAttributeChange` API.

```jsx
import {
  reactExtension,
  BlockStack,
  Button,
  Text,
  useAttributeValues,
  useApplyAttributeChange,
  useInstructions,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
  'purchase.checkout.block.render',
  () => <Extension />,
);

function Extension() {
  const [giftWrapValue] = useAttributeValues([
    'giftWrap',
  ]);
  const giftWrap = Boolean(giftWrapValue);
  const applyAttributeChange =
    useApplyAttributeChange();
  const instructions = useInstructions();

  async function toggleGiftWrap() {
    const result = giftWrap
      ? await applyAttributeChange({
          type: 'removeAttribute',
          key: 'giftWrap',
        })
      : await applyAttributeChange({
          type: 'updateAttribute',
          key: 'giftWrap',
          value: 'true',
        });
    if (result.type === 'error') {
      console.error(result.message);
    }
  }

  return (
    <BlockStack spacing="tight">
      <Text>
        Gift wrapping:{' '}
        {giftWrap ? 'Added' : 'Not set'}
      </Text>
      <Button
        onPress={toggleGiftWrap}
        disabled={
          !instructions.attributes
            .canUpdateAttributes
        }
      >
        {giftWrap
          ? 'Remove gift wrap'
          : 'Add gift wrap'}
      </Button>
    </BlockStack>
  );
}

```

```js
import {
  extension,
  BlockStack,
  Button,
  Text,
} from '@shopify/ui-extensions/checkout';

export default extension(
  'purchase.checkout.block.render',
  (
    root,
    {
      attributes,
      instructions,
      applyAttributeChange,
    },
  ) => {
    let giftWrap = false;
    const text = root.createComponent(Text);
    const button = root.createComponent(Button, {
      onPress: async () => {
        const result = giftWrap
          ? await applyAttributeChange({
              type: 'removeAttribute',
              key: 'giftWrap',
            })
          : await applyAttributeChange({
              type: 'updateAttribute',
              key: 'giftWrap',
              value: 'true',
            });
        if (result.type === 'error') {
          console.error(result.message);
        }
      },
    });
    const blockStack = root.createComponent(
      BlockStack,
      {
        spacing: 'tight',
      },
      [text, button],
    );

    attributes.subscribe(updateUI);
    instructions.subscribe(updateUI);

    function updateUI() {
      giftWrap = Boolean(
        attributes.current?.find(
          (attr) => attr.key === 'giftWrap',
        )?.value,
      );

      text.replaceChildren(
        `Gift wrapping: ${giftWrap ? 'Added' : 'Not set'}`,
      );
      button.updateProps({
        disabled:
          !instructions.current?.attributes
            ?.canUpdateAttributes,
      });
      button.replaceChildren(
        giftWrap
          ? 'Remove gift wrap'
          : 'Add gift wrap',
      );
    }
    updateUI();

    root.append(blockstack);
  },
);

```

## CheckoutApi

The API object provided to `purchase.checkout` extension targets.

### Docs_Checkout_AttributesApi

### applyAttributeChange

value: `(change: AttributeChange) => Promise<AttributeChangeResult>`

Performs an update on an attribute attached to the cart and checkout. If successful, this mutation results in an update to the value retrieved through the [`attributes`](https://shopify.dev/docs/api/checkout-ui-extensions/apis/attributes#standardapi-propertydetail-attributes) property.

> Note: This method will return an error if the [cart instruction](https://shopify.dev/docs/api/checkout-ui-extensions/apis/cart-instructions#standardapi-propertydetail-instructions) `attributes.canUpdateAttributes` is false, or the buyer is using an accelerated checkout method, such as Apple Pay, Google Pay, or Meta Pay.

### AttributeUpdateChange

Updates an attribute on the order. If an attribute with the provided key does not already exist, it gets created.

### key

value: `string`

Key of the attribute to add or update

### type

value: `"updateAttribute"`

The type of the `AttributeUpdateChange` API.

### value

value: `string`

Value for the attribute to add or update

### Attribute

### key

value: `string`

The key for the attribute.

### value

value: `string`

The value for the attribute.

### AttributeRemoveChange

Removes an attribute on the order if an attribute with the provided key already exists.

### key

value: `string`

Key of the attribute to remove

### type

value: `"removeAttribute"`

The type of the `AttributeRemoveChange` API.

### AttributeChangeResultSuccess

The returned result of a successful update to an attribute.

### type

value: `"success"`

The type of the `AttributeChangeResultSuccess` API.

### AttributeChangeResultError

The returned result of an unsuccessful update to an attribute with a message detailing the type of error that occurred.

### message

value: `string`

A message that explains the error. This message is useful for debugging. It is **not** localized, and therefore should not be presented directly to the buyer.

### type

value: `"error"`

The type of the `AttributeChangeResultError` API.

## Related

- [Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets)
- [Components](https://shopify.dev/docs/api/checkout-ui-extensions/components)
- [Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration)
- [Tutorials](/apps/checkout)

## Examples

The API for interacting with cart and checkout attributes.


You can add or remove cart and checkout attributes by using the `applyAttributeChange` API.

```jsx
import {
  reactExtension,
  BlockStack,
  Button,
  Text,
  useAttributeValues,
  useApplyAttributeChange,
  useInstructions,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
  'purchase.checkout.block.render',
  () => <Extension />,
);

function Extension() {
  const [giftWrapValue] = useAttributeValues([
    'giftWrap',
  ]);
  const giftWrap = Boolean(giftWrapValue);
  const applyAttributeChange =
    useApplyAttributeChange();
  const instructions = useInstructions();

  async function toggleGiftWrap() {
    const result = giftWrap
      ? await applyAttributeChange({
          type: 'removeAttribute',
          key: 'giftWrap',
        })
      : await applyAttributeChange({
          type: 'updateAttribute',
          key: 'giftWrap',
          value: 'true',
        });
    if (result.type === 'error') {
      console.error(result.message);
    }
  }

  return (
    <BlockStack spacing="tight">
      <Text>
        Gift wrapping:{' '}
        {giftWrap ? 'Added' : 'Not set'}
      </Text>
      <Button
        onPress={toggleGiftWrap}
        disabled={
          !instructions.attributes
            .canUpdateAttributes
        }
      >
        {giftWrap
          ? 'Remove gift wrap'
          : 'Add gift wrap'}
      </Button>
    </BlockStack>
  );
}

```

```js
import {
  extension,
  BlockStack,
  Button,
  Text,
} from '@shopify/ui-extensions/checkout';

export default extension(
  'purchase.checkout.block.render',
  (
    root,
    {
      attributes,
      instructions,
      applyAttributeChange,
    },
  ) => {
    let giftWrap = false;
    const text = root.createComponent(Text);
    const button = root.createComponent(Button, {
      onPress: async () => {
        const result = giftWrap
          ? await applyAttributeChange({
              type: 'removeAttribute',
              key: 'giftWrap',
            })
          : await applyAttributeChange({
              type: 'updateAttribute',
              key: 'giftWrap',
              value: 'true',
            });
        if (result.type === 'error') {
          console.error(result.message);
        }
      },
    });
    const blockStack = root.createComponent(
      BlockStack,
      {
        spacing: 'tight',
      },
      [text, button],
    );

    attributes.subscribe(updateUI);
    instructions.subscribe(updateUI);

    function updateUI() {
      giftWrap = Boolean(
        attributes.current?.find(
          (attr) => attr.key === 'giftWrap',
        )?.value,
      );

      text.replaceChildren(
        `Gift wrapping: ${giftWrap ? 'Added' : 'Not set'}`,
      );
      button.updateProps({
        disabled:
          !instructions.current?.attributes
            ?.canUpdateAttributes,
      });
      button.replaceChildren(
        giftWrap
          ? 'Remove gift wrap'
          : 'Add gift wrap',
      );
    }
    updateUI();

    root.append(blockstack);
  },
);

```

## useApplyAttributeChange

Returns a function to mutate the `attributes` property of the checkout.

### UseApplyAttributeChangeGeneratedType

Returns a function to mutate the `attributes` property of the checkout.

#### Returns: (change: AttributeChange) => Promise<AttributeChangeResult>
export function useApplyAttributeChange<
  Target extends RenderExtensionTarget = RenderExtensionTarget,
>(): (change: AttributeChange) => Promise<AttributeChangeResult> {
  const api = useApi<Target>();

  if ('applyAttributeChange' in api) {
    return api.applyAttributeChange;
  }

  throw new ExtensionHasNoMethodError(
    'applyAttributeChange',
    api.extension.target,
  );
}


### AttributeUpdateChange

Updates an attribute on the order. If an attribute with the provided key does not already exist, it gets created.

### key

value: `string`

Key of the attribute to add or update

### type

value: `"updateAttribute"`

The type of the `AttributeUpdateChange` API.

### value

value: `string`

Value for the attribute to add or update

### Attribute

### key

value: `string`

The key for the attribute.

### value

value: `string`

The value for the attribute.

### AttributeRemoveChange

Removes an attribute on the order if an attribute with the provided key already exists.

### key

value: `string`

Key of the attribute to remove

### type

value: `"removeAttribute"`

The type of the `AttributeRemoveChange` API.

### AttributeChangeResultSuccess

The returned result of a successful update to an attribute.

### type

value: `"success"`

The type of the `AttributeChangeResultSuccess` API.

### AttributeChangeResultError

The returned result of an unsuccessful update to an attribute with a message detailing the type of error that occurred.

### message

value: `string`

A message that explains the error. This message is useful for debugging. It is **not** localized, and therefore should not be presented directly to the buyer.

### type

value: `"error"`

The type of the `AttributeChangeResultError` API.

## Related

- [Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets)
- [Components](https://shopify.dev/docs/api/checkout-ui-extensions/components)
- [Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration)
- [Tutorials](/apps/checkout)

## Examples

The API for interacting with cart and checkout attributes.


You can add or remove cart and checkout attributes by using the `applyAttributeChange` API.

```jsx
import {
  reactExtension,
  BlockStack,
  Button,
  Text,
  useAttributeValues,
  useApplyAttributeChange,
  useInstructions,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
  'purchase.checkout.block.render',
  () => <Extension />,
);

function Extension() {
  const [giftWrapValue] = useAttributeValues([
    'giftWrap',
  ]);
  const giftWrap = Boolean(giftWrapValue);
  const applyAttributeChange =
    useApplyAttributeChange();
  const instructions = useInstructions();

  async function toggleGiftWrap() {
    const result = giftWrap
      ? await applyAttributeChange({
          type: 'removeAttribute',
          key: 'giftWrap',
        })
      : await applyAttributeChange({
          type: 'updateAttribute',
          key: 'giftWrap',
          value: 'true',
        });
    if (result.type === 'error') {
      console.error(result.message);
    }
  }

  return (
    <BlockStack spacing="tight">
      <Text>
        Gift wrapping:{' '}
        {giftWrap ? 'Added' : 'Not set'}
      </Text>
      <Button
        onPress={toggleGiftWrap}
        disabled={
          !instructions.attributes
            .canUpdateAttributes
        }
      >
        {giftWrap
          ? 'Remove gift wrap'
          : 'Add gift wrap'}
      </Button>
    </BlockStack>
  );
}

```

```js
import {
  extension,
  BlockStack,
  Button,
  Text,
} from '@shopify/ui-extensions/checkout';

export default extension(
  'purchase.checkout.block.render',
  (
    root,
    {
      attributes,
      instructions,
      applyAttributeChange,
    },
  ) => {
    let giftWrap = false;
    const text = root.createComponent(Text);
    const button = root.createComponent(Button, {
      onPress: async () => {
        const result = giftWrap
          ? await applyAttributeChange({
              type: 'removeAttribute',
              key: 'giftWrap',
            })
          : await applyAttributeChange({
              type: 'updateAttribute',
              key: 'giftWrap',
              value: 'true',
            });
        if (result.type === 'error') {
          console.error(result.message);
        }
      },
    });
    const blockStack = root.createComponent(
      BlockStack,
      {
        spacing: 'tight',
      },
      [text, button],
    );

    attributes.subscribe(updateUI);
    instructions.subscribe(updateUI);

    function updateUI() {
      giftWrap = Boolean(
        attributes.current?.find(
          (attr) => attr.key === 'giftWrap',
        )?.value,
      );

      text.replaceChildren(
        `Gift wrapping: ${giftWrap ? 'Added' : 'Not set'}`,
      );
      button.updateProps({
        disabled:
          !instructions.current?.attributes
            ?.canUpdateAttributes,
      });
      button.replaceChildren(
        giftWrap
          ? 'Remove gift wrap'
          : 'Add gift wrap',
      );
    }
    updateUI();

    root.append(blockstack);
  },
);

```

## useAttributes

Returns the proposed `attributes` applied to the checkout.

### UseAttributesGeneratedType

Returns the proposed `attributes` applied to the checkout.

#### Returns: Attribute[] | undefined
export function useAttributes<
  Target extends RenderExtensionTarget = RenderExtensionTarget,
>(): Attribute[] | undefined {
  return useSubscription(useApi<Target>().attributes);
}


### Attribute

### key

value: `string`

The key for the attribute.

### value

value: `string`

The value for the attribute.

## Related

- [Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets)
- [Components](https://shopify.dev/docs/api/checkout-ui-extensions/components)
- [Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration)
- [Tutorials](/apps/checkout)

## Examples

The API for interacting with cart and checkout attributes.


You can add or remove cart and checkout attributes by using the `applyAttributeChange` API.

```jsx
import {
  reactExtension,
  BlockStack,
  Button,
  Text,
  useAttributeValues,
  useApplyAttributeChange,
  useInstructions,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
  'purchase.checkout.block.render',
  () => <Extension />,
);

function Extension() {
  const [giftWrapValue] = useAttributeValues([
    'giftWrap',
  ]);
  const giftWrap = Boolean(giftWrapValue);
  const applyAttributeChange =
    useApplyAttributeChange();
  const instructions = useInstructions();

  async function toggleGiftWrap() {
    const result = giftWrap
      ? await applyAttributeChange({
          type: 'removeAttribute',
          key: 'giftWrap',
        })
      : await applyAttributeChange({
          type: 'updateAttribute',
          key: 'giftWrap',
          value: 'true',
        });
    if (result.type === 'error') {
      console.error(result.message);
    }
  }

  return (
    <BlockStack spacing="tight">
      <Text>
        Gift wrapping:{' '}
        {giftWrap ? 'Added' : 'Not set'}
      </Text>
      <Button
        onPress={toggleGiftWrap}
        disabled={
          !instructions.attributes
            .canUpdateAttributes
        }
      >
        {giftWrap
          ? 'Remove gift wrap'
          : 'Add gift wrap'}
      </Button>
    </BlockStack>
  );
}

```

```js
import {
  extension,
  BlockStack,
  Button,
  Text,
} from '@shopify/ui-extensions/checkout';

export default extension(
  'purchase.checkout.block.render',
  (
    root,
    {
      attributes,
      instructions,
      applyAttributeChange,
    },
  ) => {
    let giftWrap = false;
    const text = root.createComponent(Text);
    const button = root.createComponent(Button, {
      onPress: async () => {
        const result = giftWrap
          ? await applyAttributeChange({
              type: 'removeAttribute',
              key: 'giftWrap',
            })
          : await applyAttributeChange({
              type: 'updateAttribute',
              key: 'giftWrap',
              value: 'true',
            });
        if (result.type === 'error') {
          console.error(result.message);
        }
      },
    });
    const blockStack = root.createComponent(
      BlockStack,
      {
        spacing: 'tight',
      },
      [text, button],
    );

    attributes.subscribe(updateUI);
    instructions.subscribe(updateUI);

    function updateUI() {
      giftWrap = Boolean(
        attributes.current?.find(
          (attr) => attr.key === 'giftWrap',
        )?.value,
      );

      text.replaceChildren(
        `Gift wrapping: ${giftWrap ? 'Added' : 'Not set'}`,
      );
      button.updateProps({
        disabled:
          !instructions.current?.attributes
            ?.canUpdateAttributes,
      });
      button.replaceChildren(
        giftWrap
          ? 'Remove gift wrap'
          : 'Add gift wrap',
      );
    }
    updateUI();

    root.append(blockstack);
  },
);

```

## useAttributeValues

Returns the values for the specified `attributes` applied to the checkout.

### UseAttributeValuesGeneratedType

Returns the values for the specified `attributes` applied to the checkout.

#### Returns: (string | undefined)[]

#### Params:

- keys: string[]
export function useAttributeValues<
  Target extends RenderExtensionTarget = RenderExtensionTarget,
>(keys: string[]): (string | undefined)[] {
  const attributes = useAttributes<Target>();

  if (!attributes?.length) {
    return [];
  }

  return keys.map((key) => {
    const attribute = attributes.find((attribute) => attribute.key === key);
    return attribute?.value;
  });
}


## Related

- [Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets)
- [Components](https://shopify.dev/docs/api/checkout-ui-extensions/components)
- [Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration)
- [Tutorials](/apps/checkout)

## Examples

The API for interacting with cart and checkout attributes.


You can add or remove cart and checkout attributes by using the `applyAttributeChange` API.

```jsx
import {
  reactExtension,
  BlockStack,
  Button,
  Text,
  useAttributeValues,
  useApplyAttributeChange,
  useInstructions,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
  'purchase.checkout.block.render',
  () => <Extension />,
);

function Extension() {
  const [giftWrapValue] = useAttributeValues([
    'giftWrap',
  ]);
  const giftWrap = Boolean(giftWrapValue);
  const applyAttributeChange =
    useApplyAttributeChange();
  const instructions = useInstructions();

  async function toggleGiftWrap() {
    const result = giftWrap
      ? await applyAttributeChange({
          type: 'removeAttribute',
          key: 'giftWrap',
        })
      : await applyAttributeChange({
          type: 'updateAttribute',
          key: 'giftWrap',
          value: 'true',
        });
    if (result.type === 'error') {
      console.error(result.message);
    }
  }

  return (
    <BlockStack spacing="tight">
      <Text>
        Gift wrapping:{' '}
        {giftWrap ? 'Added' : 'Not set'}
      </Text>
      <Button
        onPress={toggleGiftWrap}
        disabled={
          !instructions.attributes
            .canUpdateAttributes
        }
      >
        {giftWrap
          ? 'Remove gift wrap'
          : 'Add gift wrap'}
      </Button>
    </BlockStack>
  );
}

```

```js
import {
  extension,
  BlockStack,
  Button,
  Text,
} from '@shopify/ui-extensions/checkout';

export default extension(
  'purchase.checkout.block.render',
  (
    root,
    {
      attributes,
      instructions,
      applyAttributeChange,
    },
  ) => {
    let giftWrap = false;
    const text = root.createComponent(Text);
    const button = root.createComponent(Button, {
      onPress: async () => {
        const result = giftWrap
          ? await applyAttributeChange({
              type: 'removeAttribute',
              key: 'giftWrap',
            })
          : await applyAttributeChange({
              type: 'updateAttribute',
              key: 'giftWrap',
              value: 'true',
            });
        if (result.type === 'error') {
          console.error(result.message);
        }
      },
    });
    const blockStack = root.createComponent(
      BlockStack,
      {
        spacing: 'tight',
      },
      [text, button],
    );

    attributes.subscribe(updateUI);
    instructions.subscribe(updateUI);

    function updateUI() {
      giftWrap = Boolean(
        attributes.current?.find(
          (attr) => attr.key === 'giftWrap',
        )?.value,
      );

      text.replaceChildren(
        `Gift wrapping: ${giftWrap ? 'Added' : 'Not set'}`,
      );
      button.updateProps({
        disabled:
          !instructions.current?.attributes
            ?.canUpdateAttributes,
      });
      button.replaceChildren(
        giftWrap
          ? 'Remove gift wrap'
          : 'Add gift wrap',
      );
    }
    updateUI();

    root.append(blockstack);
  },
);

```