---
title: Smart Search Input
product: Survey Creator
description: Discover how our Intelligent Auto-Complete Input and Smart Search Input components streamline data entry for industry and occupation codes by providing real-time, user-friendly suggestions, ensuring accurate and standardized data capture.
framework: jQuery
source: https://surveyjs.io/survey-creator/examples/smart-search-input/jquery
index: https://surveyjs.io/survey-creator/examples/overview.md
---

# Smart Search Input (jQuery)

Smart search is an advanced search functionality that uses personalization, context understanding, auto-suggestions, and other techniques to improve the accuracy and relevance of search results. With SurveyJS, you can implement smart search using a custom composite component. This component allows you to combine multiple built-in question types into a single element and implement custom logic to handle user input. In this demo, the custom component finds industry and occupation codes based on free-form text input from users. Industry and occupation data is provided by the <a href="https://wwwn.cdc.gov/NIOCCS/default.html" target="_blank">NIOCCS Industry and Occupation Coding Web API</a>.

To create a custom smart search component, follow the steps below:

1. Create a custom SurveyJS component.                    
Define a configuration object that implements the [`ICustomQuestionTypeConfiguration`](https://surveyjs.io/form-library/documentation/api-reference/icustomquestiontypeconfiguration) interface. Within this object, specify a unique [`name`](https://surveyjs.io/form-library/documentation/api-reference/icustomquestiontypeconfiguration#name) used to identify your component in code, a user-friendly [`title`](https://surveyjs.io/form-library/documentation/api-reference/icustomquestiontypeconfiguration#title), and a [`defaultQuestionTitle`](https://surveyjs.io/form-library/documentation/api-reference/icustomquestiontypeconfiguration#defaultQuestionTitle) to use for questions created using this component.

1. Configure input fields.          
To specify the input fields that component contains, populate the [`elementsJSON`](https://surveyjs.io/form-library/documentation/api-reference/icustomquestiontypeconfiguration#elementsJSON) array with objects. Add one or more text input fields, which will act as search boxes, and radio button groups, which will be populated with autocomplete suggestions.

1. Update autocomplete suggestions.         
Each time users change the search box value, you need to update the autocomplete suggestions. To configure this behavior, implement the [`onValueChanged`](https://surveyjs.io/form-library/documentation/api-reference/icustomquestiontypeconfiguration#onValueChanged) function.

1. Limit the maximum number of suggestions.        
A custom SurveyJS component can have its own properties that help you implement custom behavior. To add a component property, call the `Serializer.addProperty(className, propMeta)` method. Pass the `name` from step 1 as `className` and an object with property settings as `propMeta`. Call this method within the [`onInit`](https://surveyjs.io/form-library/documentation/api-reference/icustomquestiontypeconfiguration#onInit) function to add the property when the component is initialized. In this demo, we add a `maxSuggestionCount` property that specifies the maximum number of suggestions. 

1. Register the SurveyJS component.         
To make your SurveyJS component recognizable by Form Library and Survey Creator, add its configuration object to the `ComponentCollection`. Refer to the code listing for a full code example.

## Files

### `public/index.html`

```html
<!-- Uncomment the following lines to enable Ace Editor in the JSON Editor tab -->
<!-- 
<script src="https://unpkg.com/ace-builds/src-min-noconflict/ace.js"></script>
<script src="https://unpkg.com/ace-builds/src-min-noconflict/ext-searchbox.js"></script>
<script src="https://unpkg.com/ace-builds/src-min-noconflict/theme-clouds_midnight.js"></script>
-->

<div id="surveyCreatorContainer" style="position: absolute; height: 100%; width: 100%"></div>
```

### `src/index.css`

```css
/* You can add your custom CSS here. */
```

### `src/survey_json.js`

```js
export const surveyJSON = {
  "title": "Employment and Work Environment Survey",
  "pages": [
    {
      "name": "employmentAndWorkEnvironment",
      "elements": [
        {
          "type": "occupation-industry-autocomplete",
          "name": "industryAndOccupation",
          "maxSuggestionCount": 4
        }
      ]
    }
  ]
}
```

### `src/index.js`

```js
import { SurveyCreator } from "survey-creator-js";
import "survey-core/survey.i18n";
import "survey-creator-core/survey-creator-core.i18n";
import { ComponentCollection, Serializer } from "survey-core";
import { surveyJSON } from "./survey_json";
import "survey-core/survey-core.css";
import "survey-creator-core/survey-creator-core.css";
import "./index.css";

import SurveyTheme from "survey-core/themes";
import { registerCreatorTheme } from "survey-creator-core";

registerCreatorTheme(SurveyTheme); // Add predefined Survey Creator UI themes

const QUESTION_TYPE_OCCUPATION = "occupation-industry-autocomplete";

// Step 1: Create a custom SurveyJS component
const smartSearchComponent = {
    name: QUESTION_TYPE_OCCUPATION,
    title: "Industry and Occupation",
    defaultQuestionTitle: "Industry and Occupation",
    // Industry information will be fetched from https://wwwn.cdc.gov/nioccs/IOCode
    industrySuggestedChoices: [],
    // Occupation information will be fetched from https://wwwn.cdc.gov/nioccs/IOCode
    occupationSuggestedChoices: [],
    // Step 2: Configure input fields
    elementsJSON: [
        {
            type: "text",
            name: "userInputIndustry",
            title: "Describe your industry or business (do not enter a company name)",
            description: "For example: community hospital, elementary education, insurance agency, automobile manufacturing, apple orchard.",
            textUpdateMode: "onTyping",
            placeholder: "Enter your industry"
        },
        {
            type: "text",
            name: "userInputOccupation",
            title: "Describe your occupation",
            description: "For example: emergency room nurse, second-grade teacher, office manager, spot welder, fruit grower.",
            textUpdateMode: "onTyping",
            placeholder: "Enter your occupation"
        },
        {
            type: "radiogroup",
            name: "industryCode",
            title: "Please select an industry",
            hideIfChoicesEmpty: true
        },
        {
            type: "radiogroup",
            name: "occupationCode",
            title: "Please select an occupation",
            hideIfChoicesEmpty: true
        },
        {
            type: "text",
            name: "details",
            clearIfInvisible: "none",
            visible: false
        },
    ],
    // Step 3: Update autocomplete suggestions when users change the search box value
    onValueChanged(question, name, newValue) {
        if (name === "userInputOccupation" || name === "userInputIndustry") {
            const { industry, occupation } = this.maybeRefetch(question);
            this.getIndustryCodeQuestion(question).isRequired = !!industry || !!occupation;
            this.getOccupationCodeQuestion(question).isRequired = !!industry || !!occupation;
            this.getIndustryCodeQuestion(question).visible = !!industry && !!occupation;
            this.getOccupationCodeQuestion(question).visible = !!industry && !!occupation;
        }
        if (name === "industryCode" && !!newValue) {
            const code = this.getIndustryCodeQuestion(question).value;
            const selectedIndustry = this.industrySuggestedChoices.find(
                (industry) => industry.NAICSCode === code
            );
            const answer = {
                ...this.getDetailsQuestion(question).value,
                Industry: selectedIndustry,
            };
            this.getDetailsQuestion(question).value = answer;
        }
        if (name === "occupationCode" && !!newValue) {
            const code = this.getOccupationCodeQuestion(question).value;
            const selectedOccupation = this.occupationSuggestedChoices.find(
                (occupation) => occupation.SOCCode === code
            );
            const answer = {
                ...this.getDetailsQuestion(question).value,
                Occupation: selectedOccupation,
            };
            this.getDetailsQuestion(question).value = answer;
        }
        return newValue;
    },
    sendRequest(question, industry, occupation) {
        const baseUrl = "https://wwwn.cdc.gov/nioccs/IOCode";
        const params = {
            c: 2,
            u: 0,
            v: 18,
            n: question.maxSuggestionCount + 1,
            t: "json",
            i: industry,
            o: occupation,
        };
        const queryString = Object.keys(params)
            .map(
                (key) => encodeURIComponent(key) + "=" + encodeURIComponent(params[key])
            )
            .join("&");
        const url = `${baseUrl}?${queryString}`;

        fetch(url)
            .then((response) => response.json())
            .then((data) => {
                this.industrySuggestedChoices = data.Industry;
                this.occupationSuggestedChoices = data.Occupation;
                this.updateIndustryChoices(
                    question,
                    data.Industry.map((item) => ({
                        Code: item.NAICSCode,
                        Title: item.NAICSTitle,
                    }))
                );
                this.updateOccupationChoices(
                    question,
                    data.Occupation.map((item) => ({
                        Code: item.SOCCode,
                        Title: item.SOCTitle,
                    }))
                );
            });
    },
    maybeRefetch(question) {
        const industry = this.getUserInputIndustryQuestion(question).value;
        const occupation = this.getUserInputOccupationQuestion(question).value;
        if (industry && occupation) {
            this.sendRequest(question, industry, occupation);
        }
        return { industry, occupation };
    },
    updateOccupationChoices(question, data) {
        this.updateChoices(this.getOccupationCodeQuestion(question), data, question.maxSuggestionCount);
    },
    updateIndustryChoices(question, data) {
        this.updateChoices(this.getIndustryCodeQuestion(question), data, question.maxSuggestionCount);
    },
    updateChoices(codeQuestion, data, maxChoices) {
        if (codeQuestion) {
            const choices = [];
            const prevValue = codeQuestion.value;
            let hasValue = false;
            data.forEach((item) => {
                if (item.Title !== "Insufficient Information" && choices.length < maxChoices) {
                    hasValue = hasValue || (prevValue && prevValue === item.Code);
                    choices.push({ value: item.Code, text: item.Title });
                }
            });
            choices.push({ value: "-", text: "None of the above" });
            codeQuestion.choices = choices;
            if (prevValue && !hasValue) {
                codeQuestion.clearValue();
            }
        }
    },
    getUserInputIndustryQuestion(question) {
        return this.getQuestionByName(question, "userInputIndustry");
    },
    getUserInputOccupationQuestion(question) {
        return this.getQuestionByName(question, "userInputOccupation");
    },
    getIndustryCodeQuestion(question) {
        return this.getQuestionByName(question, "industryCode");
    },
    getOccupationCodeQuestion(question) {
        return this.getQuestionByName(question, "occupationCode");
    },
    getDetailsQuestion(question) {
        return this.getQuestionByName(question, "details");
    },
    getQuestionByName(question, name) {
        return question.contentPanel.getQuestionByName(name);
    },
    // Step 4: Limit the maximum number of suggestions
    onInit() {
        Serializer.addProperty(QUESTION_TYPE_OCCUPATION, {
            name: "maxSuggestionCount:number",
            default: 3,
            choices: [1, 2, 3, 4, 5, 6, 7],
            category: "general",
            visibleIndex: 2,
        });
    },
    onValueSet(question) {
        this.maybeRefetch(question);
        this.updateChoicesOnSetValue(
            this.getOccupationCodeQuestion(question),
            this.getDetailsQuestion(question).value?.Occupation?.SOCTitle
        );
        this.updateChoicesOnSetValue(
            this.getIndustryCodeQuestion(question),
            this.getDetailsQuestion(question).value?.Industry?.NAICSTitle
        );
    },
    updateChoicesOnSetValue(codeQuestion, titleValue) {
        if (codeQuestion.choices.length === 0 && titleValue) {
            codeQuestion.choices = [{ value: codeQuestion.value, text: titleValue }];
        }
    }
}

// Step 5: Register the SurveyJS component
if (!ComponentCollection.Instance.getCustomQuestionByName(QUESTION_TYPE_OCCUPATION)) {
    ComponentCollection.Instance.add(smartSearchComponent)
}
const creator = new SurveyCreator();
creator.JSON = surveyJSON;
creator.activeTab = "test";
creator.render("surveyCreatorContainer");
```

### `package.json`

```json
{
  "dependencies": {
    "jquery": "latest",
    "survey-core": "latest",
    "survey-js-ui": "latest",
    "survey-creator-core": "latest",
    "survey-creator-js": "latest"
  },
  "devDependencies": {
    "react-scripts": "latest"
  }
}
```

## Other Frameworks

- [Angular](https://surveyjs.io/survey-creator/examples/smart-search-input/angular.md)
- [React](https://surveyjs.io/survey-creator/examples/smart-search-input/reactjs.md)
- [Vue 3](https://surveyjs.io/survey-creator/examples/smart-search-input/vue3js.md)
- [Vanilla JS](https://surveyjs.io/survey-creator/examples/smart-search-input/vanillajs.md)
