---
title: Continue an Incomplete Survey
product: Form Library
description: Learn how to enable users to continue incomplete surveys with this free demo for JavaScript. Ensure seamless survey experience across sessions by saving and restoring survey responses from localStorage.
framework: React
source: https://surveyjs.io/form-library/examples/save-and-restore-user-responses-to-complete-survey/reactjs
index: https://surveyjs.io/form-library/examples/overview.md
---

# Continue an Incomplete Survey (React)

Respondents may not complete your survey in a single session. In this case, you can restore their answers from the previous session next time they get to the survey. Incomplete results can be loaded from your database or the browser's [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). This demo shows how to save and restore incomplete survey results and the last visited question and page from the `localStorage`. To test this functionality, answer a couple of questions and reload the page. Your answers should persist. For information on how to save incomplete results on a server, refer to the following help topic: [Restore Survey Progress from a Database](/form-library/documentation/how-to-save-and-restore-incomplete-survey#restore-survey-progress-from-a-database). 

## Save Incomplete Survey Results

To save incomplete results, implement functions that send survey data and UI state to your server or store them in the `localStorage` (see the `saveSurveyData` and `saveSurveyUIState` functions in the code). Call these functions inside the `SurveyModel`'s [`onValueChanged`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onValueChanged) and [`onUIStateChanged`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onUIStateChanged) event handlers to capture updates whenever users change a value or modify the UI (for example, expand/collapse a question box or switch pages). If you use the `localStorage`, also handle the [`onComplete`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onComplete) event to submit the final results to the server and remove them from the `localStorage`, as they no longer need to be restored.

> `localStorage` is limited to 5 MB of data per domain. If you expect incomplete responses to exceed this limit (which may happen if they contain encoded images or files), [store them in a database](/form-library/documentation/how-to-save-and-restore-incomplete-survey#restore-survey-progress-from-a-database).

## Restore Survey Progress

To restore results, retrieve the saved data from your server or `localStorage` and assign it to the `SurveyModel`'s [`data`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#data) property. If you've also stored the UI state, assign it to the [`uiState`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#uiState) property.

## Files

### `public/index.html`

```html
<div id="surveyElement" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; min-height: 100%; height:100%"></div>
```

### `src/SurveyComponent.jsx`

```js
import React from "react";
import { Model } from "survey-core";
import { Survey } from "survey-react-ui";
import "survey-core/survey-core.min.css";
import "./index.css";
import { json } from "./json";

const STORAGE_ITEM_DATA_KEY = "my-survey-data";
const STORAGE_ITEM_UI_STATE_KEY = "my-survey-state";

function saveSurveyData(survey) {
    window.localStorage.setItem(STORAGE_ITEM_DATA_KEY, JSON.stringify(survey.data));
}

function saveSurveyUIState(survey) {
    window.localStorage.setItem(STORAGE_ITEM_UI_STATE_KEY, JSON.stringify(survey.uiState));
}

function clearStorage() {
    window.localStorage.setItem(STORAGE_ITEM_DATA_KEY, "");
    window.localStorage.setItem(STORAGE_ITEM_UI_STATE_KEY, "");
}
function SurveyComponent() {
    const survey = new Model(json);
    survey.onComplete.add((sender, options) => {
        console.log(JSON.stringify(sender.data, null, 3));
    });
    // Save survey results and UI state to the local storage
    survey.onValueChanged.add(saveSurveyData);
    survey.onUIStateChanged.add(saveSurveyUIState);
    
    // Restore survey results
    const prevData = window.localStorage.getItem(STORAGE_ITEM_DATA_KEY) || null;
    if (prevData) {
        const data = JSON.parse(prevData);
        survey.data = data;
    }
    
    // Restore the survey UI state
    const prevState = window.localStorage.getItem(STORAGE_ITEM_UI_STATE_KEY) || null;
    if (prevState) {
        const state = JSON.parse(prevState);
        survey.uiState = state;
    }
    
    // Empty the local storage after the survey is completed
    survey.onComplete.add(clearStorage);
    return (<Survey model={survey} />);
}

export default SurveyComponent;
```

### `src/index.css`

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

### `src/index.js`

```js
import React from "react";
import { createRoot } from "react-dom/client";
import SurveyComponent from "./SurveyComponent";

const root = createRoot(document.getElementById("surveyElement"));
root.render(<SurveyComponent />);
```

### `src/json.js`

```js
export const json = {
  "pages": [{
    "name": "page1",
    "elements": [{
      "type": "matrix",
      "name": "qualities",
      "title": "Please indicate if you agree or disagree with the following statements",
      "columns": [{
        "value": 5,
        "text": "Strongly agree"
      }, {
        "value": 4,
        "text": "Agree"
      }, {
        "value": 3,
        "text": "Neutral"
      }, {
        "value": 2,
        "text": "Disagree"
      }, {
        "value": 1,
        "text": "Strongly disagree"
      }],
      "rows": [{
        "value": "affordable",
        "text": "Product is affordable"
      }, {
        "value": "does-what-it-claims",
        "text": "Product does what it claims"
      }, {
        "value": "better-than-others",
        "text": "Product is better than other products on the market"
      },{
        "value": "easy-to-use",
        "text": "Product is easy to use"
      }]
    }, {
      "type": "rating",
      "name": "satisfaction-score",
      "title": "How satisfied are you with our product?",
      "minRateDescription": "Not satisfied",
      "maxRateDescription": "Completely satisfied"
    }, {
      "type": "checkbox",
      "name": "favourite-features",
      "title": "Which product features do you value most?",
      "description": "The options are presented in a randomized order, which is preserved in the UI state.",
      "choices": [
        "Ease of use",
        "Performance",
        "Customization options",
        "Integrations",
        "Customer support"
      ],
      "choicesOrder": "random"
    }, {
      "type": "rating",
      "name": "recommend",
      "visibleIf": "{satisfaction-score} > 3",
      "title": "How likely are you to recommend our product to a friend or co-worker?",
      "minRateDescription": "Will not recommend",
      "maxRateDescription": "I will recommend"
    }, {
      "type": "comment",
      "name": "suggestions",
      "title": "What would make you more satisfied with our product?"
    }]
  }, {
    "name": "page2",
    "elements": [{
      "type": "radiogroup",
      "name": "price-comparison",
      "title": "Compared to our competitors, do you feel our product is:",
      "choices": [
        "Less expensive",
        "Priced about the same",
        "More expensive",
        "Not sure"
      ]
    }, {
      "type": "radiogroup",
      "name": "current-price",
      "title": "Do you feel our current price is merited by our product?",
      "choices": [{
        "value": "correct",
        "text": "Yes, the price is about right"
      }, {
        "value": "low",
        "text": "No, the price is too low for your product"
      }, {
        "value": "high",
        "text": "No, the price is too high for your product"
      }]
    }, {
      "type": "multipletext",
      "name": "price-limits",
      "title": "What is the highest and lowest price you would pay for a product like ours?",
      "items": [{
        "name": "highest",
        "title": "Highest"
      }, {
        "name": "lowest",
        "title": "Lowest"
      }],
      "itemTitleWidth": "60px"
    }]
  }, {
    "name": "page3",
    "elements": [{
      "type": "text",
      "name": "email",
      "title": "Please leave your email address if you would like us to contact you."
    }]
  }]
};
```

### `src/theme.js`

```js
export const themeJson = {};
```

### `package.json`

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

## Other Frameworks

- [Angular](https://surveyjs.io/form-library/examples/save-and-restore-user-responses-to-complete-survey/angular.md)
- [Vue 3](https://surveyjs.io/form-library/examples/save-and-restore-user-responses-to-complete-survey/vue3js.md)
- [jQuery](https://surveyjs.io/form-library/examples/save-and-restore-user-responses-to-complete-survey/jquery.md)
- [Vanilla JS](https://surveyjs.io/form-library/examples/save-and-restore-user-responses-to-complete-survey/vanillajs.md)
