Skip to main content

GL Search

Version: 1.0.14
Package: @gift-card-market/gl-search
Last Updated: January 16, 2026


A reusable React search component with location input and Google Maps integration for Gift Card Market.

Version License

Features

  • 🔍 Search with Location - Integrated Google Maps location autocomplete
  • 🎨 Customizable UI - Configure banner colors, texts, and search button styling
  • Debounced Search - Configurable debounce time for better performance
  • 🎯 Custom Events - Dispatch search and clear events for easy integration
  • 📱 Responsive Design - Works seamlessly on all devices
  • 🌐 Vanilla JS Support - Use as Web Component without React
  • 💪 TypeScript - Full type definitions included

Table of Contents


Installation

Using npm

npm install @gift-card-market/gl-search

Using yarn

yarn add @gift-card-market/gl-search

Integration

React Integration

1. Import the Component and Styles

import { GlSearch } from '@gift-card-market/gl-search';
import '@gift-card-market/gl-search/dist/style.css';

2. Basic Usage

import React from 'react';
import { GlSearch } from '@gift-card-market/gl-search';
import '@gift-card-market/gl-search/dist/style.css';

function App() {
return (
<div>
<GlSearch
environment="development"
jwt="your-jwt-token-here"
/>
</div>
);
}

export default App;

3. Advanced Usage with All Options

import React, { useRef } from 'react';
import { GlSearch } from '@gift-card-market/gl-search';
import type { GlSearchBarHandle } from '@gift-card-market/gl-search';
import '@gift-card-market/gl-search/dist/style.css';

function App() {
const searchRef = useRef<GlSearchBarHandle>(null);

// Configuration data
const searchData = {
banner_color: 'darkblue',
banner_text: [
`Search for your <strong>favorite</strong> restaurants! 🍔`,
`Find the perfect gift card 🎁`,
],
search_text: [
{
content: `(thinking <u>top burger joints</u>?)`,
key: 'burgers',
},
{
content: `(thinking <u>best pizza places</u>?)`,
key: 'pizza',
},
],
search_term: '',
search_button_color: {
text: 'yellow',
background: 'green',
},
};

return (
<div>
<GlSearch
ref={searchRef}
environment="development"
jwt="your-jwt-token-here"
google_api_key="your-google-api-key"
data={searchData}
debounce_ms={250}
query="Location=New York&SearchTerm=pizza"
/>
</div>
);
}

export default App;

Vanilla JS Integration

1. Include Scripts and Styles

After publishing, include the bundled JavaScript and CSS files from the dist/browser folder:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GlSearch - Vanilla JS Demo</title>

<!-- Include the bundled JS and CSS from published package -->
<script src="../../node_modules/@gift-card-market/gl-search/dist/browser/gl-search.global.js"></script>
<link rel="stylesheet" href="../../node_modules/@gift-card-market/gl-search/dist/browser/gl-search.css">
</head>
<body>
<div id="search-container"></div>

<script>
// Your initialization code here
</script>
</body>
</html>

2. Basic Usage

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GlSearch - Vanilla JS Demo</title>

<script src="../../node_modules/@gift-card-market/gl-search/dist/browser/gl-search.global.js"></script>
<link rel="stylesheet" href="../../node_modules/@gift-card-market/gl-search/dist/browser/gl-search.css">
</head>
<body>
<div id="search-container"></div>

<script>
// Initialize the web component
function initializeComponent() {
const container = document.getElementById('search-container');

// Create the custom element
const searchElement = document.createElement('gl-search');

// Set required attributes
searchElement.setAttribute('environment', 'development');
searchElement.setAttribute('jwt', 'your-jwt-token-here');

// Append to container
container.appendChild(searchElement);
}

// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeComponent);
} else {
initializeComponent();
}
</script>
</body>
</html>

3. Advanced Usage with All Options

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GlSearch - Vanilla JS Advanced Demo</title>

<script src="../../node_modules/@gift-card-market/gl-search/dist/browser/gl-search.global.js"></script>
<link rel="stylesheet" href="../../node_modules/@gift-card-market/gl-search/dist/browser/gl-search.css">
</head>
<body>
<div id="search-container"></div>

<script>
// Configuration data
const searchData = {
banner_color: 'darkblue',
banner_text: [
`Search for your <strong>favorite</strong> restaurants! 🍔`,
`Find the perfect gift card 🎁`,
],
search_text: [
{
content: `(thinking <u>top burger joints</u>?)`,
key: 'burgers',
},
{
content: `(thinking <u>best pizza places</u>?)`,
key: 'pizza',
},
],
search_term: '',
search_button_color: {
text: 'yellow',
background: 'green',
},
};

// Store reference to the web component
let searchElement = null;

// Initialize the web component
function initializeComponent() {
const container = document.getElementById('search-container');

// Create the custom element
searchElement = document.createElement('gl-search');

// Set required attributes
searchElement.setAttribute('environment', 'development');
searchElement.setAttribute('jwt', 'your-jwt-token-here');

// Set optional attributes
searchElement.setAttribute('google_api_key', 'your-google-api-key');
searchElement.setAttribute('debounce_ms', '250');
searchElement.setAttribute('query', 'Location=New York&SearchTerm=pizza');

// Set data as JSON string
searchElement.setAttribute('data', JSON.stringify(searchData));

// Append to container
container.appendChild(searchElement);

console.log('Web Component initialized successfully');
}

// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeComponent);
} else {
initializeComponent();
}
</script>
</body>
</html>

API Reference

Props / Attributes

PropertyTypeRequiredDefaultDescription
environmentstring✅ Yes-Environment mode: 'development', 'qa', 'staging' or 'production'
jwtstring✅ Yes-JWT authentication token
google_api_keystringNo-Google Maps API key for location autocomplete
debounce_msnumberNo250Debounce time in milliseconds for search input
querystringNo-Initial search query (format: 'Location=...&SearchTerm=...')
dataobjectNo{}Configuration object (see below)

Data Object Structure

{
banner_color?: string; // Banner background color
banner_text?: string[]; // Array of rotating banner texts (supports HTML)
search_text?: Array<{ // Array of search placeholder suggestions
content: string; // Placeholder text (supports HTML)
key: string; // Search term key
}>;
search_term?: string; // Initial search term
search_button_color?: { // Search button styling
text: string; // Text color
background: string; // Background color
};
}

Ref Methods (React Only)

When using React, you can access component methods via ref:

interface GlSearchBarHandle {
focus: () => void; // Focus on the location input field
setQuery: (query: string) => void; // Set search query programmatically
}

Example Usage

import React, { useRef } from 'react';
import { GlSearch } from '@gift-card-market/gl-search';
import type { GlSearchBarHandle } from '@gift-card-market/gl-search';

function App() {
const searchRef = useRef<GlSearchBarHandle>(null);

const handleFocus = () => {
searchRef.current?.focus();
};

const handleSetQuery = () => {
searchRef.current?.setQuery('Location=New York&SearchTerm=pizza');
};

return (
<div>
<button onClick={handleFocus}>Focus Input</button>
<button onClick={handleSetQuery}>Set Query</button>

<GlSearch
ref={searchRef}
environment="development"
jwt="your-jwt-token"
/>
</div>
);
}

Vanilla JS Methods

In Vanilla JS, you can call methods directly on the DOM element:

const searchElement = document.querySelector('gl-search');

// Focus on input
searchElement.focus();

// Set query
searchElement.setQuery('Location=New York&SearchTerm=pizza');

Custom Events

The component dispatches custom events that you can listen to for search interactions.

Available Events

Event NameDescriptionEvent Detail
gl:searchDispatched when a search is performed{ query: string }
gl:clearDispatched when the search is cleared{}

Event Handling

React Event Handling

import React, { useEffect } from 'react';
import { GlSearch, SearchBarEvents } from '@gift-card-market/gl-search';
import '@gift-card-market/gl-search/dist/style.css';

function App() {
useEffect(() => {
// Listen to search event
const handleSearch = (e: CustomEvent) => {
console.log('Search performed:', e.detail);
// e.detail.query contains: "Location=...&SearchTerm=...&SortBy=...&ProviderId=..."

// Parse query string
const params = new URLSearchParams(e.detail.query);
const location = params.get('Location');
const searchTerm = params.get('SearchTerm');

console.log('Location:', location);
console.log('Search Term:', searchTerm);

// Perform your search logic here
// e.g., fetch data from API, update state, etc.
};

// Listen to clear event
const handleClear = (e: CustomEvent) => {
console.log('Search cleared:', e.detail);
// Reset your search results, state, etc.
};

// Add event listeners
document.addEventListener(SearchBarEvents.SEARCH, handleSearch as EventListener);
document.addEventListener(SearchBarEvents.CLEAR, handleClear as EventListener);

// Cleanup
return () => {
document.removeEventListener(SearchBarEvents.SEARCH, handleSearch as EventListener);
document.removeEventListener(SearchBarEvents.CLEAR, handleClear as EventListener);
};
}, []);

return (
<div>
<GlSearch
environment="development"
jwt="your-jwt-token"
/>
</div>
);
}

export default App;

Vanilla JS Event Handling

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GlSearch - Event Handling</title>

<script src="../../node_modules/@gift-card-market/gl-search/dist/browser/gl-search.global.js"></script>
<link rel="stylesheet" href="../../node_modules/@gift-card-market/gl-search/dist/browser/gl-search.css">
</head>
<body>
<div id="search-container"></div>

<script>
// Initialize the component
function initializeComponent() {
const container = document.getElementById('search-container');
const searchElement = document.createElement('gl-search');

searchElement.setAttribute('environment', 'development');
searchElement.setAttribute('jwt', 'your-jwt-token');

container.appendChild(searchElement);
}

// Listen to search event
document.addEventListener('gl:search', function(e) {
console.log('Search performed:', e.detail);

// Parse query string
const params = new URLSearchParams(e.detail.query);
const location = params.get('Location');
const searchTerm = params.get('SearchTerm');

console.log('Location:', location);
console.log('Search Term:', searchTerm);

// Perform your search logic here
// e.g., fetch data from API, update UI, etc.
});

// Listen to clear event
document.addEventListener('gl:clear', function(e) {
console.log('Search cleared:', e.detail);
// Reset your search results, UI, etc.
});

// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeComponent);
} else {
initializeComponent();
}
</script>
</body>
</html>

Complete Examples

React Complete Example

import React, { useRef, useEffect, useState } from 'react';
import { GlSearch, SearchBarEvents } from '@gift-card-market/gl-search';
import type { GlSearchBarHandle } from '@gift-card-market/gl-search';
import '@gift-card-market/gl-search/dist/style.css';

function App() {
const searchRef = useRef<GlSearchBarHandle>(null);
const [searchResults, setSearchResults] = useState([]);
const [loading, setLoading] = useState(false);

// Configuration
const searchData = {
banner_color: 'darkblue',
banner_text: [
`Do they love burgers? 🍔 Search for their <strong style="color: #ffe606">favorite</strong> below.`,
`You've got <strong style="color: #ffe606">great taste</strong>. We've got gift cards to match.`,
],
search_text: [
{
content: `(thinking <u>top smash burger joints</u>?)`,
key: 'smash burgers',
},
{
content: `(thinking <u>best lunch spots near me</u>?)`,
key: 'best lunch spots',
},
],
search_term: '',
search_button_color: {
text: 'yellow',
background: 'green',
},
};

useEffect(() => {
// Handle search event
const handleSearch = async (e: CustomEvent) => {
console.log('Search event:', e.detail);

setLoading(true);

try {
// Parse query parameters
const params = new URLSearchParams(e.detail.query);
const location = params.get('Location');
const searchTerm = params.get('SearchTerm');

// Call your API
const response = await fetch(`/api/search?location=${location}&term=${searchTerm}`);
const data = await response.json();

setSearchResults(data.results);
} catch (error) {
console.error('Search error:', error);
} finally {
setLoading(false);
}
};

// Handle clear event
const handleClear = (e: CustomEvent) => {
console.log('Clear event:', e.detail);
setSearchResults([]);
};

// Add listeners
document.addEventListener(SearchBarEvents.SEARCH, handleSearch as EventListener);
document.addEventListener(SearchBarEvents.CLEAR, handleClear as EventListener);

// Cleanup
return () => {
document.removeEventListener(SearchBarEvents.SEARCH, handleSearch as EventListener);
document.removeEventListener(SearchBarEvents.CLEAR, handleClear as EventListener);
};
}, []);

// Handler functions for buttons
const handleFocus = () => {
searchRef.current?.focus();
};

const handleSetQuery = () => {
searchRef.current?.setQuery('Location=New York&SearchTerm=pizza');
};

return (
<div className="app">
{/* Control buttons */}
<div style={{ padding: '20px', background: '#f5f5f5' }}>
<button onClick={handleFocus}>Focus Input</button>
<button onClick={handleSetQuery}>Set Query (NY/Pizza)</button>
</div>

{/* Search component */}
<GlSearch
ref={searchRef}
environment="development"
jwt="your-jwt-token"
google_api_key="your-google-api-key"
data={searchData}
debounce_ms={250}
/>

{/* Results */}
{loading && <div>Loading...</div>}
{searchResults.length > 0 && (
<div className="results">
{searchResults.map((result, index) => (
<div key={index}>{/* Render your results */}</div>
))}
</div>
)}
</div>
);
}

export default App;

Vanilla JS Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GlSearch - Complete Vanilla JS Example</title>

<!-- Include scripts and styles from published package -->
<script src="../../node_modules/@gift-card-market/gl-search/dist/browser/gl-search.global.js"></script>
<link rel="stylesheet" href="../../node_modules/@gift-card-market/gl-search/dist/browser/gl-search.css">

<style>
body {
margin: 0;
font-family: Arial, sans-serif;
}
.control-panel {
padding: 20px;
background: #f5f5f5;
border-bottom: 2px solid #ddd;
}
.control-panel button {
margin-right: 10px;
padding: 10px 20px;
background: #4CAF50;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
.results {
padding: 20px;
}
.loading {
text-align: center;
padding: 20px;
font-size: 18px;
}
</style>
</head>
<body>
<!-- Control Panel -->
<div class="control-panel">
<button onclick="handleFocus()">🎯 Focus Input</button>
<button onclick="handleSetQuery()">📝 Set Query (NY/Pizza)</button>
</div>

<!-- Search Container -->
<div id="search-container"></div>

<!-- Results Container -->
<div id="results-container"></div>

<script>
// Configuration
const searchData = {
banner_color: 'darkblue',
banner_text: [
`Do they love burgers? 🍔 Search for their <strong style="color: #ffe606">favorite</strong> below.`,
`You've got <strong style="color: #ffe606">great taste</strong>. We've got gift cards to match.`,
],
search_text: [
{
content: `(thinking <u>top smash burger joints</u>?)`,
key: 'smash burgers',
},
{
content: `(thinking <u>best lunch spots near me</u>?)`,
key: 'best lunch spots',
},
],
search_term: '',
search_button_color: {
text: 'yellow',
background: 'green',
},
};

// Store reference to the web component
let searchElement = null;

// Initialize the web component
function initializeComponent() {
const container = document.getElementById('search-container');

// Create the custom element
searchElement = document.createElement('gl-search');

// Set required attributes
searchElement.setAttribute('environment', 'development');
searchElement.setAttribute('jwt', 'your-jwt-token');

// Set optional attributes
searchElement.setAttribute('google_api_key', 'your-google-api-key');
searchElement.setAttribute('debounce_ms', '250');
searchElement.setAttribute('data', JSON.stringify(searchData));

// Append to container
container.appendChild(searchElement);

console.log('Component initialized');
}

// Handle search event
document.addEventListener('gl:search', async function(e) {
console.log('Search performed:', e.detail);

const resultsContainer = document.getElementById('results-container');
resultsContainer.innerHTML = '<div class="loading">Loading...</div>';

try {
// Parse query parameters
const params = new URLSearchParams(e.detail.query);
const location = params.get('Location');
const searchTerm = params.get('SearchTerm');

console.log('Location:', location);
console.log('Search Term:', searchTerm);

// Call your API
const response = await fetch(`/api/search?location=${location}&term=${searchTerm}`);
const data = await response.json();

// Display results
resultsContainer.innerHTML = '<div class="results"><h2>Search Results</h2>' +
data.results.map(result => `<div>${result.name}</div>`).join('') +
'</div>';

} catch (error) {
console.error('Search error:', error);
resultsContainer.innerHTML = '<div class="results">Error loading results</div>';
}
});

// Handle clear event
document.addEventListener('gl:clear', function(e) {
console.log('Search cleared:', e.detail);
document.getElementById('results-container').innerHTML = '';
});

// Method to focus input
function handleFocus() {
if (searchElement) {
searchElement.focus();
console.log('Input focused');
}
}

// Method to set query
function handleSetQuery() {
if (searchElement) {
searchElement.setQuery('Location=New York&SearchTerm=pizza');
console.log('Query set');
}
}

// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeComponent);
} else {
initializeComponent();
}
</script>
</body>
</html>

TypeScript Support

This package includes full TypeScript definitions. Import types as needed:

import type {
GlSearchProps,
GlSearchBarHandle,
SearchBarEventType
} from '@gift-card-market/gl-search';
import { SearchBarEvents } from '@gift-card-market/gl-search';

Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

License

ISC © Gift Card Market


Support

For issues and questions, please visit:


Contributing

Contributions are welcome! Please refer to the project's contributing guidelines.


Changelog

Version 1.0.14

  • Current stable release
  • Full React and Vanilla JS support
  • Custom event system
  • TypeScript definitions included