> ## 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

> Learn how to programmatically open the chat widget and send a message.

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">Available 24/7</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 and auto-send control theme={null}
window.Molin.openChat({ message, autoSend });
```

### 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 });
```

### 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>

**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

## 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' });
}
```
