> ## Documentation Index
> Fetch the complete documentation index at: https://docs.molin.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Send message programmatically

> Use the openChat API to programmatically open the chat window and send a message on the customer's behalf from your own code.

export const OpenChatPlayground = () => {
  const [message, setMessage] = useState('Hello! I need help with my order');
  const [autoSend, setAutoSend] = useState(true);
  const [status, setStatus] = useState(null);
  const showStatus = (text, type) => {
    setStatus({
      text,
      type
    });
    setTimeout(() => {
      setStatus(null);
    }, 5000);
  };
  const sendMessage = () => {
    if (typeof window !== 'undefined' && window.Molin && window.Molin.openChat) {
      try {
        window.Molin.openChat({
          message,
          autoSend
        });
        showStatus('✅ Message sent via window.Molin.openChat()', 'success');
      } catch (err) {
        showStatus('❌ Error: ' + err.message, 'error');
      }
    } else {
      showStatus('⚠️ Molin widget not loaded. Make sure the widget script is installed on this page.', 'warning');
    }
  };
  const sendMessageWithSelector = () => {
    if (typeof window !== 'undefined') {
      const molinWidget = document.querySelector('molin-shop-ai');
      if (molinWidget && typeof molinWidget.openChat === 'function') {
        try {
          molinWidget.openChat({
            message,
            autoSend
          });
          showStatus("✅ Message sent via querySelector('molin-shop-ai')", 'success');
        } catch (err) {
          showStatus('❌ Error: ' + err.message, 'error');
        }
      } else {
        showStatus('⚠️ Molin widget element not found. Make sure the widget script is installed on this page.', 'warning');
      }
    }
  };
  return <div className="my-5 rounded-lg border border-gray-300 bg-gray-50 p-5 dark:border-gray-600 dark:bg-gray-800">
      <h4 className="mt-0 mb-4 text-lg font-semibold text-gray-800 dark:text-gray-200">OpenChat API Playground</h4>

      <div className="mb-4">
        <label htmlFor="message-input" className="mb-1 block font-semibold text-gray-700 dark:text-gray-300">
          Message:
        </label>
        <input type="text" id="message-input" placeholder="Enter your message here..." value={message} onChange={e => setMessage(e.target.value)} className="w-full rounded border border-gray-300 bg-white p-2.5 text-sm text-gray-900 focus:border-transparent focus:ring-2 focus:ring-[#601FEB] dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100" />
      </div>

      <div className="mb-4">
        <label className="flex cursor-pointer items-center">
          <input type="checkbox" checked={autoSend} onChange={e => setAutoSend(e.target.checked)} className="mr-2 h-4 w-4 rounded border-gray-300 bg-gray-100 text-[#601FEB] focus:ring-2 focus:ring-[#601FEB] dark:border-gray-500 dark:bg-gray-600" />
          <span className="font-semibold text-gray-700 dark:text-gray-300">Auto-send message</span>
        </label>
        <small className="ml-5 text-gray-500 dark:text-gray-400">When unchecked, the message will only be prefilled</small>
      </div>

      <div className="flex gap-2.5">
        <button onClick={sendMessage} className="flex-1 cursor-pointer rounded border-none bg-[#601FEB] px-5 py-2.5 font-semibold text-white transition-colors duration-200 hover:bg-[#8624FF]">
          Send Message (window.Molin)
        </button>
        <button onClick={sendMessageWithSelector} className="flex-1 cursor-pointer rounded border-none bg-emerald-600 px-5 py-2.5 font-semibold text-white transition-colors duration-200 hover:bg-emerald-700">
          Send Message (querySelector)
        </button>
      </div>

      {status && <div className={`mt-4 rounded border p-2.5 text-sm ${status.type === 'success' ? 'border-green-200 bg-green-50 text-green-800 dark:border-green-800 dark:bg-green-900/20 dark:text-green-300' : status.type === 'error' ? 'border-red-200 bg-red-50 text-red-800 dark:border-red-800 dark:bg-red-900/20 dark:text-red-300' : 'border-yellow-200 bg-yellow-50 text-yellow-800 dark:border-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-300'}`}>
          {status.text}
        </div>}
    </div>;
};

export const ProductGrid = () => {
  const products = [{
    id: 1,
    name: 'Nomad Pouch',
    href: '#',
    price: '$50',
    availability: 'White and Black',
    imageSrc: 'https://tailwindcss.com/plus-assets/img/ecommerce-images/category-page-07-product-01.jpg',
    imageAlt: 'White fabric pouch with white zipper, black zipper pull, and black elastic loop.',
    type: 'product'
  }, {
    id: 2,
    name: 'Zip Tote Basket',
    href: '#',
    price: '$140',
    availability: 'Washed Black',
    imageSrc: 'https://tailwindcss.com/plus-assets/img/ecommerce-images/category-page-07-product-02.jpg',
    imageAlt: 'Front of tote bag with washed black canvas body, black straps, and tan leather handles and accents.',
    type: 'product'
  }, {
    id: 3,
    name: 'Medium Stuff Satchel',
    href: '#',
    price: '$220',
    availability: 'Blue',
    imageSrc: 'https://tailwindcss.com/plus-assets/img/ecommerce-images/category-page-07-product-03.jpg',
    imageAlt: 'Front of satchel with blue canvas body, black straps and handle, drawstring top, and front zipper pouch.',
    type: 'product'
  }, {
    id: 4,
    name: 'High Wall Tote',
    href: '#',
    price: '$210',
    availability: 'Black and Orange',
    imageSrc: 'https://tailwindcss.com/plus-assets/img/ecommerce-images/category-page-07-product-04.jpg',
    imageAlt: 'Front of zip tote bag with black canvas, black handles, and orange drawstring top.',
    type: 'product'
  }, {
    id: 5,
    name: 'Not finding what you are looking for?',
    href: '#',
    price: '',
    availability: 'Get personalized recommendations and assistance',
    imageSrc: '',
    imageAlt: 'AI expert consultation',
    type: 'ai-expert'
  }, {
    id: 6,
    name: 'Zip High Wall Tote',
    href: '#',
    price: '$150',
    availability: 'White and blue',
    imageSrc: 'https://tailwindcss.com/plus-assets/img/ecommerce-images/category-page-07-product-06.jpg',
    imageAlt: 'Front of zip tote bag with white canvas, blue canvas straps and handle, and front zipper pocket.',
    type: 'product'
  }];
  const handleAIExpertClick = () => {
    if (typeof window !== 'undefined' && window.Molin && window.Molin.openChat) {
      window.Molin.openChat({
        message: 'I need help finding the right product. Can you assist me with personalized recommendations?',
        autoSend: true
      });
    } else {
      alert('Would open chat with AI expert for personalized recommendations');
    }
  };
  return <div className="bg-white dark:bg-gray-900">
      <div className="mx-auto max-w-7xl overflow-hidden px-4 py-16 sm:px-6 sm:py-24 lg:px-8">
        <div className="grid grid-cols-1 gap-x-6 gap-y-10 sm:grid-cols-2 lg:grid-cols-3 lg:gap-x-8">
          {products.map(product => product.type === 'ai-expert' ? <button key={product.id} onClick={handleAIExpertClick} className="group rounded-lg text-left text-sm transition-all duration-200 focus:ring-2 focus:ring-purple-500 focus:ring-offset-2 focus:outline-none">
                {}
                <div className="flex aspect-square w-full flex-col items-center justify-center rounded-lg border-2 border-purple-400 bg-gradient-to-br from-purple-200 to-blue-200 transition-all duration-200 group-hover:border-purple-600 group-hover:bg-gradient-to-br group-hover:from-purple-300 group-hover:to-blue-300 dark:border-purple-600 dark:from-purple-800/20 dark:to-blue-800/20 dark:group-hover:border-purple-400 dark:group-hover:from-purple-700/30 dark:group-hover:to-blue-700/30">
                  <div className="my-2 rounded-full bg-white p-3 shadow-sm transition-shadow group-hover:shadow-md dark:bg-gray-800">
                    <svg className="h-6 w-6 text-purple-500 dark:text-purple-400" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                      <path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z" />
                      <path d="M20 3v4" />
                      <path d="M22 5h-4" />
                      <path d="M4 17v2" />
                      <path d="M5 18H3" />
                    </svg>
                  </div>
                  <div className="px-4 text-center">
                    <p className="mb-2 text-sm text-gray-600 dark:text-gray-300">{product.availability}</p>
                    <div className="rounded-full bg-purple-500 px-4 py-2 text-xs font-medium text-white transition-colors group-hover:bg-purple-600 dark:bg-purple-600 dark:group-hover:bg-purple-500">
                      Talk to our AI expert
                    </div>
                  </div>
                </div>
                <h3 className="mt-4 font-medium text-gray-900 dark:text-gray-100">{product.name}</h3>
                <p className="mt-2 text-sm font-medium text-purple-600 dark:text-purple-400">AI-powered</p>
              </button> : <a key={product.id} href={product.href} className="group text-sm">
                {}
                <img alt={product.imageAlt} src={product.imageSrc || '/placeholder.svg'} className="aspect-square w-full rounded-lg bg-gray-100 object-cover group-hover:opacity-75 dark:bg-gray-800" />
                <h3 className="mt-4 font-medium text-gray-900 dark:text-gray-100">{product.name}</h3>
                <p className="text-gray-500 italic dark:text-gray-400">{product.availability}</p>
                <p className="mt-2 font-medium text-gray-900 dark:text-gray-100">{product.price}</p>
              </a>)}
        </div>
      </div>
    </div>;
};

export const SearchAutocomplete = () => {
  const [query, setQuery] = useState('');
  const [isOpen, setIsOpen] = useState(false);
  const [selectedIndex, setSelectedIndex] = useState(-1);
  const inputRef = useRef(null);
  const suggestionRefs = useRef([]);
  const getSuggestions = searchQuery => {
    if (!searchQuery.trim()) return [];
    const suggestions = [{
      id: 'ai-search',
      type: 'ai',
      title: `${searchQuery}`,
      subtitle: 'Get intelligent results powered by AI',
      icon: <svg className="h-5 w-5 text-purple-500" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z" />
            <path d="M20 3v4" />
            <path d="M22 5h-4" />
            <path d="M4 17v2" />
            <path d="M5 18H3" />
          </svg>
    }, {
      id: 'product-1',
      type: 'product',
      title: `Pro Max`,
      subtitle: 'Premium quality product with advanced features',
      icon: <svg className="h-5 w-5 text-blue-500" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z" />
            <path d="M12 22V12" />
            <polyline points="3.29 7 12 12 20.71 7" />
            <path d="m7.5 4.27 9 5.15" />
          </svg>
    }, {
      id: 'product-2',
      type: 'product',
      title: `Essential`,
      subtitle: 'Affordable option with core functionality',
      icon: <svg className="h-5 w-5 text-green-500" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z" />
            <path d="M12 22V12" />
            <polyline points="3.29 7 12 12 20.71 7" />
            <path d="m7.5 4.27 9 5.15" />
          </svg>
    }];
    return suggestions;
  };
  const suggestions = getSuggestions(query);
  const handleInputChange = e => {
    const value = e.target.value;
    setQuery(value);
    setIsOpen(value.length > 0);
    setSelectedIndex(-1);
  };
  const handleKeyDown = e => {
    if (!isOpen || suggestions.length === 0) {
      return;
    }
    switch (e.key) {
      case 'ArrowDown':
        e.preventDefault();
        setSelectedIndex(prev => prev < suggestions.length - 1 ? prev + 1 : 0);
        break;
      case 'ArrowUp':
        e.preventDefault();
        setSelectedIndex(prev => prev > 0 ? prev - 1 : suggestions.length - 1);
        break;
      case 'Enter':
        e.preventDefault();
        if (selectedIndex >= 0) {
          handleSuggestionClick(suggestions[selectedIndex]);
        }
        break;
      case 'Escape':
        setIsOpen(false);
        setSelectedIndex(-1);
        inputRef.current?.blur();
        break;
    }
  };
  const handleSuggestionClick = suggestion => {
    setQuery(suggestion.title);
    setIsOpen(false);
    setSelectedIndex(-1);
    if (typeof window !== 'undefined' && window.Molin && window.Molin.openChat) {
      window.Molin.openChat({
        message: suggestion.title,
        autoSend: true
      });
    } else {
      alert(`Would open chat with message: "${suggestion.title}"`);
    }
  };
  const handleInputFocus = () => {
    if (query.length > 0) {
      setIsOpen(true);
    }
  };
  const handleInputBlur = () => {
    setTimeout(() => {
      setIsOpen(false);
      setSelectedIndex(-1);
    }, 200);
  };
  useEffect(() => {
    if (selectedIndex >= 0 && suggestionRefs.current[selectedIndex]) {
      suggestionRefs.current[selectedIndex]?.scrollIntoView({
        block: 'nearest',
        behavior: 'smooth'
      });
    }
  }, [selectedIndex]);
  return <div className="relative mx-auto w-full max-w-2xl">
      {}
      <div className="relative">
        <div className="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
          <svg className="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="m21 21-4.34-4.34" />
            <circle cx="11" cy="11" r="8" />
          </svg>
        </div>
        <input ref={inputRef} type="text" value={query} onChange={handleInputChange} onKeyDown={handleKeyDown} onFocus={handleInputFocus} onBlur={handleInputBlur} placeholder="Search for products..." className="block w-full rounded-lg border border-gray-300 bg-white py-3 pr-3 pl-10 leading-5 text-gray-900 placeholder-gray-500 shadow-sm focus:border-transparent focus:placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:outline-none" />
      </div>

      {}
      {isOpen && suggestions.length > 0 && <div className="ring-opacity-5 absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-lg bg-white py-1 text-base shadow-lg ring-1 ring-black focus:outline-none">
          {suggestions.map((suggestion, index) => <div key={suggestion.id} ref={el => suggestionRefs.current[index] = el} onClick={() => handleSuggestionClick(suggestion)} className={`relative cursor-pointer px-4 py-3 select-none hover:bg-gray-50 ${index === selectedIndex ? 'bg-blue-50' : ''} ${suggestion.type === 'ai' ? 'border-b border-gray-100' : ''}`}>
              <div className="flex items-center space-x-3">
                {}
                <div className="flex-shrink-0">{suggestion.icon}</div>

                {}
                <div className="min-w-0 flex-1">
                  <div className="flex items-center space-x-2">
                    <p className="my-1 truncate text-sm font-medium text-gray-900">{suggestion.title}</p>
                  </div>
                  <p className="my-0.5 truncate text-sm text-gray-500">{suggestion.subtitle}</p>
                </div>

                {}
                {index === selectedIndex && <div className="flex-shrink-0">
                    <div className="h-2 w-2 rounded-full bg-blue-500"></div>
                  </div>}
              </div>
            </div>)}
        </div>}

      {}
      {isOpen && query.length > 0 && suggestions.length === 0 && <div className="ring-opacity-5 absolute z-10 mt-1 w-full rounded-lg bg-white px-4 py-3 text-base shadow-lg ring-1 ring-black">
          <p className="text-sm text-gray-500">No suggestions found</p>
        </div>}
    </div>;
};

export const AutoSendExample = () => {
  const sendSupportMessage = type => {
    let message = '';
    switch (type) {
      case 'order':
        message = "I need help with my order status. Can you please check what's happening with my recent purchase?";
        break;
      case 'return':
        message = 'I would like to return an item I purchased. Can you help me with the return process?';
        break;
      case 'billing':
        message = 'I have a question about my billing. There seems to be an issue with my last payment.';
        break;
      default:
        message = 'I need help with something';
    }
    if (typeof window !== 'undefined' && window.Molin && window.Molin.openChat) {
      window.Molin.openChat({
        message,
        autoSend: true
      });
    } else {
      alert(`Demo: Would auto-send message: "${message}"`);
    }
  };
  return <div className="rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-800">
      <h3 className="mt-0 mb-4 text-lg font-semibold text-gray-800 dark:text-gray-200">Auto-send Message Example</h3>
      <p className="mb-4 text-gray-600 dark:text-gray-400">Quick support buttons that automatically send specific messages:</p>

      <div className="space-y-3">
        <button onClick={() => sendSupportMessage('order')} className="flex w-full items-center justify-center gap-2 rounded-md bg-[#601FEB] px-4 py-3 font-medium text-white transition-colors duration-200 hover:bg-[#8624FF] dark:bg-[#601FEB] dark:hover:bg-[#8624FF]">
          <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 11V7a4 4 0 00-8 0v4M5 9h14l-1 12H6L5 9z" />
          </svg>
          Order Status Help
        </button>

        <button onClick={() => sendSupportMessage('return')} className="flex w-full items-center justify-center gap-2 rounded-md bg-[#601FEB] px-4 py-3 font-medium text-white transition-colors duration-200 hover:bg-[#8624FF] dark:bg-[#601FEB] dark:hover:bg-[#8624FF]">
          <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" />
          </svg>
          Return Item
        </button>

        <button onClick={() => sendSupportMessage('billing')} className="flex w-full items-center justify-center gap-2 rounded-md bg-[#601FEB] px-4 py-3 font-medium text-white transition-colors duration-200 hover:bg-[#8624FF] dark:bg-[#601FEB] dark:hover:bg-[#8624FF]">
          <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" />
          </svg>
          Billing Question
        </button>
      </div>
    </div>;
};

export const ProductInquiryExample = () => {
  const [selectedColor, setSelectedColor] = useState('black');
  const [selectedSize, setSelectedSize] = useState('s');
  const sampleProduct = {
    name: "Women's Basic Tee",
    description: 'Premium cotton blend t-shirt with comfortable fit and modern styling',
    price: 32,
    rating: 3.9,
    reviews: 512,
    image: 'https://tailwindcss.com/plus-assets/img/ecommerce-images/product-page-01-featured-product-shot.jpg'
  };
  const handleAskAI = () => {
    const message = `I have questions about the product pricing, availability, and features. Can you help me with that?`;
    if (typeof window !== 'undefined' && window.Molin && window.Molin.openChat) {
      window.Molin.openChat({
        message,
        autoSend: false
      });
    } else {
      alert(`Would open chat with message: "${message}"`);
    }
  };
  const handleAddToBag = e => {
    e.preventDefault();
  };
  return <div className="mb-4 rounded-lg border border-gray-200 bg-white p-6 dark:border-gray-700 dark:bg-gray-900">
      <div className="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-12 lg:gap-x-8">
        {}
        <img src={sampleProduct.image} alt={sampleProduct.name} noZoom className="aspect-[2/3] w-full rounded-lg bg-gray-100 object-cover sm:col-span-4 lg:col-span-5" />

        {}
        <div className="sm:col-span-8 lg:col-span-7">
          <h2 className="text-xl font-medium text-gray-900 dark:text-gray-100">{sampleProduct.name}</h2>

          <section aria-labelledby="information-heading" className="mt-1">
            <h3 id="information-heading" className="sr-only">
              Product information
            </h3>
            <p className="font-medium text-gray-900 dark:text-gray-100">${sampleProduct.price}</p>

            {}
            <div className="mt-4">
              <h4 className="sr-only">Reviews</h4>
              <div className="flex items-center">
                <p className="text-sm text-gray-700 dark:text-gray-300">
                  {sampleProduct.rating}
                  <span className="sr-only"> out of 5 stars</span>
                </p>
                <div className="ml-1 flex items-center">
                  {[...Array(5)].map((_, i) => <svg key={i} className={`h-5 w-5 shrink-0 ${i < Math.floor(sampleProduct.rating) ? 'text-yellow-400' : 'text-gray-200'}`} viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
                      <path fillRule="evenodd" d="M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401Z" clipRule="evenodd" />
                    </svg>)}
                </div>
                <div className="ml-4 hidden lg:flex lg:items-center">
                  <span className="text-gray-300" aria-hidden="true">
                    ·
                  </span>
                  <a href="#" className="ml-4 text-sm font-medium text-[#601FEB] hover:text-[#8624FF] dark:text-[#7c3aed] dark:hover:text-[#8b5cf6]">
                    See all {sampleProduct.reviews} reviews
                  </a>
                </div>
              </div>
            </div>
          </section>

          <section aria-labelledby="options-heading" className="mt-8">
            <h3 id="options-heading" className="sr-only">
              Product options
            </h3>

            <form onSubmit={handleAddToBag}>
              {}
              <fieldset aria-label="Choose a color">
                <legend className="text-sm font-medium text-gray-900 dark:text-gray-100">Color</legend>
                <div className="mt-2 flex items-center gap-x-3">
                  <div className="flex rounded-full outline -outline-offset-1 outline-black/10">
                    <input aria-label="Black" type="radio" name="color" value="black" checked={selectedColor === 'black'} onChange={e => setSelectedColor(e.target.value)} className="h-8 w-8 appearance-none rounded-full bg-gray-900 forced-color-adjust-none checked:outline checked:outline-2 checked:outline-offset-2 checked:outline-gray-900 focus-visible:outline focus-visible:outline-[3px] focus-visible:outline-offset-[3px]" />
                  </div>
                  <div className="flex rounded-full outline -outline-offset-1 outline-black/10">
                    <input aria-label="Heather Grey" type="radio" name="color" value="heather-grey" checked={selectedColor === 'heather-grey'} onChange={e => setSelectedColor(e.target.value)} className="h-8 w-8 appearance-none rounded-full bg-gray-400 forced-color-adjust-none checked:outline checked:outline-2 checked:outline-offset-2 checked:outline-gray-400 focus-visible:outline focus-visible:outline-[3px] focus-visible:outline-offset-[3px]" />
                  </div>
                </div>
              </fieldset>

              {}
              <fieldset className="mt-8" aria-label="Choose a size">
                <div className="flex items-center justify-between">
                  <div className="text-sm font-medium text-gray-900 dark:text-gray-100">Size</div>
                  <a href="#" className="text-sm font-medium text-[#601FEB] hover:text-[#8624FF] dark:text-[#7c3aed] dark:hover:text-[#8b5cf6]">
                    Size guide
                  </a>
                </div>
                <div className="mt-2 grid grid-cols-4 gap-3">
                  {['xxs', 'xs', 's', 'm', 'l', 'xl'].map(size => <label key={size} aria-label={size.toUpperCase()} className={`group relative flex items-center justify-center rounded-md border border-gray-300 bg-white p-3 dark:border-gray-600 dark:bg-gray-800 ${size === 'xl' ? 'opacity-25' : ''} has-[:checked]:border-[#601FEB] has-[:checked]:bg-[#601FEB] has-[:disabled]:border-gray-400 has-[:disabled]:bg-gray-200 has-[:disabled]:opacity-25 has-[:focus-visible]:outline has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-[#601FEB] dark:has-[:disabled]:border-gray-600 dark:has-[:disabled]:bg-gray-700`}>
                      <input type="radio" name="size" value={size} checked={selectedSize === size} onChange={e => setSelectedSize(e.target.value)} disabled={size === 'xl'} className="absolute inset-0 appearance-none focus:outline focus:outline-0 disabled:cursor-not-allowed" />
                      <span className="text-sm font-medium text-gray-900 uppercase group-has-[:checked]:text-white dark:text-gray-100">{size.toUpperCase()}</span>
                    </label>)}
                </div>
              </fieldset>

              {}
              <div className="mt-8 space-y-3">
                <button type="submit" className="flex w-full items-center justify-center rounded-md border border-transparent bg-[#601FEB] px-8 py-3 text-base font-medium text-white transition-colors hover:bg-[#8624FF] focus:ring-2 focus:ring-[#601FEB] focus:ring-offset-2 focus:outline-none dark:bg-[#601FEB] dark:hover:bg-[#8624FF] dark:focus:ring-offset-gray-900">
                  Add to bag
                </button>

                <button type="button" onClick={handleAskAI} className="flex w-full items-center justify-center gap-2 rounded-md border border-[#601FEB] bg-white px-8 py-3 text-base font-medium text-[#601FEB] transition-colors hover:bg-[#601FEB]/5 focus:ring-2 focus:ring-[#601FEB] focus:ring-offset-2 focus:outline-none dark:border-[#7c3aed] dark:bg-gray-800 dark:text-[#7c3aed] dark:hover:bg-[#601FEB]/10 dark:focus:ring-offset-gray-900">
                  <svg className="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
                  </svg>
                  Ask AI about this product
                </button>
              </div>
            </form>
          </section>
        </div>
      </div>
    </div>;
};

export const BasicChatButton = () => {
  const openChat = () => {
    if (typeof window !== 'undefined' && window.Molin && window.Molin.openChat) {
      window.Molin.openChat();
    } else {
      alert('Molin widget not loaded. This is just a demo.');
    }
  };
  return <div className="rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-800">
      <h3 className="mt-0 mb-4 text-lg font-semibold text-gray-800 dark:text-gray-200">Basic Usage Example</h3>
      <p className="mb-4 text-gray-600 dark:text-gray-400">Simple button that opens the chat widget</p>

      <button onClick={openChat} className="rounded-md bg-[#601FEB] px-4 py-2 font-medium text-white transition-colors duration-200 hover:bg-[#8624FF] dark:bg-[#601FEB] dark:hover:bg-[#8624FF]">
        Chat with us
      </button>
    </div>;
};

## Overview

The `openChat` API allows you to programmatically open the chat window and send a message on behalf of the user. This is useful for:

* Sending automated support requests based on user actions
* Creating contextual help buttons that send specific inquiries
* Triggering chat conversations from forms, errors, or page events
* Automating customer service workflows

<Note>For controlling widget visibility, see [Show/Hide Widget](/apis/experimental/show-hide-widget).</Note>

<Tip>
  **No code required?** You can also open the chat via URL parameters without any JavaScript. See [Open chat via URL](/home/general/url-prefill) for a simple way to create links for marketing
  campaigns, emails, and QR codes.
</Tip>

## Method

The widget exposes this method for opening the chat:

```javascript Open chat with optional message, auto-send, and fullscreen control theme={null}
window.Molin.openChat({ message, autoSend, fullscreen });
```

### Alternative method (web component)

You can also use the web component selector:

```javascript Open chat using web component selector theme={null}
document.querySelector('molin-shop-ai').openChat({ message, autoSend, fullscreen });
```

### Parameters

<ParamField body="options" type="object" optional>
  Optional configuration object. Can be omitted entirely to simply open the chat without any message. When provided, can contain the following optional properties:

  <ParamField body="message" type="string" optional>
    The message to send when opening the chat. If omitted, the chat opens without any pre-filled message.
  </ParamField>

  <ParamField body="autoSend" type="boolean" optional default="false">
    Whether to automatically send the message. When `false` (default), the message will only be prefilled in the input field for the user to review and send manually. When `true`, the message is sent
    immediately.
  </ParamField>

  <ParamField body="fullscreen" type="boolean" optional default="false">
    Whether to open the chat window filling the whole screen on desktop. When `false` (default), the chat opens in the normal floating window. On mobile the chat is always fullscreen regardless of
    this setting.
  </ParamField>
</ParamField>

**Valid function calls:**

* `openChat()` - Opens chat without any message
* `openChat({ message: "Hello" })` - Opens chat with pre-filled message (not sent)
* `openChat({ message: "Hello", autoSend: true })` - Opens chat and sends message immediately
* `openChat({ fullscreen: true })` - Opens chat fullscreen on desktop

## Open the launcher in fullscreen by default

The `fullscreen` option above controls a single `openChat` call. To make the launcher (the floating bubble) and every other affordance open the chat fullscreen on desktop by default, set it once at the widget level.

Set it before the widget loads via `window.molinSettings`:

```html theme={null}
<script>
  window.molinSettings = {
    fullscreen: true,
  };
</script>
```

Or add the `fullscreen` attribute to the embed tag:

```html theme={null}
<molin-shop-ai widget="your-widget-id" fullscreen></molin-shop-ai>
```

A per-call `openChat({ fullscreen })` always wins over this default, so a specific button can still open the normal floating window. On mobile the chat is always fullscreen regardless of this setting.

## Examples

### Basic Usage - Open Chat Button

<BasicChatButton />

```javascript Basic Usage lines icon="js" theme={null}
// Method 1:
window.Molin.openChat();

// Method 2:
document.querySelector('molin-shop-ai').openChat();
```

### Pre-filled Message - Product Inquiry

<ProductInquiryExample />

```javascript Pre-filled Message lines wrap icon="js" theme={null}
// Method 1:
window.Molin.openChat({
  message: 'I have questions about the product pricing, availability, and features. Can you help me with that?',
  autoSend: false,
});

// Method 2:
document.querySelector('molin-shop-ai').openChat({
  message: 'I have questions about the product pricing, availability, and features. Can you help me with that?',
  autoSend: false,
});
```

### Auto-send Messages - Support Scenarios

<AutoSendExample />

<CodeGroup>
  ```javascript Order Status Help lines wrap icon="js" theme={null}
  // Method 1:
  window.Molin.openChat({
    message:
      "I need help with my order status. Can you please check what's happening with my recent purchase?",
    autoSend: false,
  })

  // Method 2:
  document.querySelector("molin-shop-ai").openChat({
  message:
  "I need help with my order status. Can you please check what's happening with my recent purchase?",
  autoSend: false,
  })

  ```

  ```javascript Return Item lines wrap icon="js" theme={null}
  // Method 1:
  window.Molin.openChat({
    message:
      "I would like to return an item I purchased. Can you help me with the return process?",
    autoSend: false,
  })

  // Method 2:
  document.querySelector("molin-shop-ai").openChat({
    message:
      "I would like to return an item I purchased. Can you help me with the return process?",
    autoSend: false,
  })
  ```

  ```javascript Billing Questions lines wrap icon="js" theme={null}
  // Method 1:
  window.Molin.openChat({
    message: 'I have a question about my billing. There seems to be an issue with my last payment.',
    autoSend: false,
  });

  // Method 2:
  document.querySelector('molin-shop-ai').openChat({
    message: 'I have a question about my billing. There seems to be an issue with my last payment.',
    autoSend: false,
  });
  ```
</CodeGroup>

### Smart Search with AI Integration

<SearchAutocomplete />

```javascript AI Search Integration theme={null}
// When user searches, open chat with search context
const searchQuery = 'wireless headphones';
window.Molin.openChat({
  message: `I'm looking for: ${searchQuery}. Can you help me find what I need?`,
  autoSend: false,
});
```

<Note>The search component integrates AI assistance with product search, allowing users to get personalized recommendations through the chat widget.</Note>

### Product Grid with AI Expert

<ProductGrid />

```javascript Product Grid with AI Expert theme={null}
// When user clicks on AI expert card
window.Molin.openChat({
  message: 'I need help finding the right product. Can you assist me with personalized recommendations?',
  autoSend: false,
});
```

<Note>The product grid includes an AI expert consultation option that opens the chat widget with a pre-filled message for personalized assistance.</Note>

## Interactive Playground

Try the openChat API with this interactive example:

<OpenChatPlayground />

<Note>
  This playground will only work if the Molin widget is installed on this documentation page. If you're viewing this in the documentation, it may show a warning that the widget is not loaded.
</Note>

## Technical note

The `openChat` method is only available after the widget script has loaded. The recommended approach is to listen for the [`molin:ready`](/home/marketing/javascript-events#molinready) event:

```javascript theme={null}
window.addEventListener('molin:ready', () => {
  window.Molin.openChat({ message: 'Your message here' });
});
```

Alternatively, you can check if `window.Molin` already exists:

```javascript theme={null}
if (window.Molin && window.Molin.openChat) {
  window.Molin.openChat({ message: 'Your message here' });
}
```
