Example - Add to cart with personalization (mockData.json)

Use a text input to collect a personalization value and add it as a line item attribute. Includes a mockData.json example.

This example collects a short personalization string (for example, initials) and adds it as a line item attribute when adding to cart.

It also includes a mockData.json example so you can test useVariables() locally.

Code

import * as React from 'react';
import { Button, Text } from '@tapcart/mobile-components';

function isValid(value, maxLength) {
  if (!value) return true;
  if (value.length > maxLength) return false;
  return /^[a-zA-Z0-9\s-]*$/.test(value);
}

export default function AddToCartPersonalizationExample({
  pageState,
  useActions,
  useSearchParams,
  useVariables,
  blockConfig,
}) {
  const { addToCart } = useActions();
  const searchParams = useSearchParams();
  const variables = useVariables();

  const productId = searchParams.get('productId') || pageState?.searchParams?.productId;
  const variantId = searchParams.get('variantId') || pageState?.searchParams?.variantId;

  const maxLength = blockConfig?.maxLength ?? 12;

  const [value, setValue] = React.useState('');
  const [isAdding, setIsAdding] = React.useState(false);

  const customerName = variables?.customer?.firstName || 'there';

  const valid = isValid(value, maxLength);
  const disabled = isAdding || !productId || !variantId || !valid;

  const handleAdd = async () => {
    if (disabled) return;

    setIsAdding(true);
    try {
      await addToCart({
        lines: [
          {
            productId,
            variantId,
            quantity: 1,
            attributes: [
              {
                key: 'Personalization',
                value: value.trim() || 'None',
              },
            ],
          },
        ],
      });
    } finally {
      setIsAdding(false);
    }
  };

  return (
    <div style={{ padding: '16px' }}>
      <Text type="body">Hi {customerName}. Add a note to this item:</Text>

      <input
        value={value}
        onChange={(e) => setValue(e.target.value)}
        placeholder="Example: JH"
        style={{
          marginTop: '12px',
          width: '100%',
          padding: '10px 12px',
          border: '1px solid #ddd',
          borderRadius: '8px',
        }}
      />

      {!valid ? (
        <Text type="body" style={{ marginTop: '8px' }}>
          Use letters, numbers, spaces, and dashes only (max {maxLength} characters).
        </Text>
      ) : null}

      <div style={{ marginTop: '12px' }}>
        <Button onClick={handleAdd} disabled={disabled}>
          {isAdding ? 'Adding…' : 'Add to cart'}
        </Button>
      </div>
    </div>
  );
}

Manifest

[
  {
    "id": "maxLength",
    "label": "Max characters",
    "type": "range",
    "defaultValue": 12,
    "min": 1,
    "max": 30,
    "unit": "",
    "step": 1
  }
]

mockData.json (optional)

Place mockData.json next to code.jsx while developing locally.

{
  "customer": {
    "id": "<UUID>",
    "firstName": "Taylor"
  }
}

Notes

  • This example assumes it’s placed on a product page (PDP) where productId and variantId are present in the page params.

Back to Examples