---
title: Custom Previews for File Upload Questions
product: Form Library
description: With SurveyJS form builder tool, you can create custom file previews for File Upload questions. This free demo for JavaScript offers a step-by-step guide on how to override the built-in preview functionality by adjusting the showPreview property and how to render personalized previews using the onAfterRenderQuestion event handler. 
framework: Vanilla JS
source: https://surveyjs.io/form-library/examples/custom-file-previews/vanillajs
index: https://surveyjs.io/form-library/examples/overview.md
---

# Custom Previews for File Upload Questions (Vanilla JS)

SurveyJS File Upload questions support the file preview functionality out of the box (see the [File Upload](/form-library/examples/file-upload/) demo). This example demonstrates how you can override this functionality and implement custom file previews if required.

To implement custom file previews, follow the steps below:

1. Disable built-in file previews.      
Set the File Upload question's [`showPreview`](/form-library/documentation/api-reference/file-model#showPreview) property to `false`.

1. Implement a custom file preview component.       
In this demo, a custom component adds a `<div>` element to the bottom of the question. When users select one or multiple files for upload, this `<div>` displays "Download file" and "Remove file" buttons per uploaded file.

1. Register your custom component under the `sv-file-preview` name.      
    In HTML/CSS/JavaScript projects, register the component in `ReactElementFactory` as shown in the `index.js` file.           
    In React, register the component in `ReactElementFactory` as shown in the `FilePreviewComponent.jsx` file.          
    In Angular, register the component in `AngularComponentFactory` as shown in the `file-preview.component.ts` file.              
    In Vue.js, register the component in `ComponentFactory` as shown in the `main.ts` file.

> In this demo, files are uploaded to SurveyJS servers from where they are then deleted after a predefined period of time. We strongly encourage you to use your own servers for file uploads when you use SurveyJS to collect sensitive respondent data in your application.

## 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/index.css`

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

### `src/FilePreviewComponent.css`

```css
.my-preview-container {
    margin-top: 2em;
    max-width: calc(100% - 64px);
    margin-bottom: 1em;
    padding-left: 1em;
    padding-right: 1em;
    box-sizing: border-box;
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    bottom: 0;
}

.btn {
    appearance: none;
    border: 1px solid lightgray;
    cursor: pointer;
    padding: 4px 8px;
    color: var(--sjs2-color-fg-brand-on-primary, #fff);
    font-weight: 600;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.button-container {
    width: 100%;
    display: flex;
    gap: 8px;
}

.btn--choose {
    background-color: var(--sjs2-color-project-brand-600, #19b394);
    overflow: hidden;
    flex: 1 1 auto;
}

.btn--choose:hover {
    background-color: var(--sjs2-color-bg-brand-primary-dim, rgb(20, 164, 139));
}

.btn--remove {
    background-color: var(--sjs2-color-bg-alert-primary, #e60a3e);
}

.btn--remove:hover {
    background-color: rgb(217, 4, 49);
}
  
```

### `src/FilePreviewComponent.js`

```js
import { createElement } from "survey-js-ui";
import "./FilePreviewComponent.css";
import { SurveyElementBase, ReactElementFactory } from "survey-js-ui";

class FilePreviewComponent extends SurveyElementBase {
    constructor(props) {
        super(props);
        this.state = {
            question: props.question
        };
    }
    downloadFile = (fileItem) => {
        fetch(fileItem.content)
            .then((response) => response.blob())
            .then((blob) => {
                const file = new File([blob], fileItem.name, {
                    type: fileItem.type
                });
                const reader = new FileReader();
                reader.onload = (e) => {
                    const a = document.createElement("a");
                    a.href = e.target.result;
                    a.download = fileItem.name;
                    a.click();
                };
                reader.readAsDataURL(file);
            })
            .catch((error) => {
                console.error("Error:", error);
            });
    };
    render() {
        const { question } = this.state;
        if (!question || !question.value) {
            return null;
        }
        const isReadOnly = question.isReadOnly || (question.survey && question.survey.readOnly);

        return (
            <div className="my-preview-container">
                <div className="files-container">
                    {question.value.map((fileItem) => (
                        <div className="button-container" key={fileItem.name}>
                            <div
                                className="btn btn--choose"
                                onClick={() => this.downloadFile(fileItem)}
                            >
                                {"Download " + fileItem.name}
                            </div>
                            <div
                                className={`btn btn--remove ${isReadOnly ? 'disabled' : ''}`}
                                onClick={() => !isReadOnly && this.state.question.removeFile(fileItem.name)}
                                title="Remove file"
                                style={{ cursor: isReadOnly ? 'not-allowed' : 'pointer', opacity: isReadOnly ? 0.5 : 1 }}
                            >
                                {"X"}
                            </div>
                        </div>
                    ))}
                </div>
            </div>
        );
    }
}

window.React = { createElement: createElement };

ReactElementFactory.Instance.registerElement("sv-file-preview", (props) => {
    return createElement(FilePreviewComponent, props);
});
```

### `src/index.js`

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

const survey = new Model(json);
survey.onComplete.add((sender, options) => {
    console.log(JSON.stringify(sender.data, null, 3));
});
survey.onUploadFiles.add((_, options) => {
    const formData = new FormData();
    options.files.forEach((file) => {
        formData.append(file.name, file);
    });

    fetch("https://api.surveyjs.io/private/Surveys/uploadTempFiles", {
        method: "POST",
        body: formData
    })
        .then((response) => response.json())
        .then((data) => {
            options.callback(
                options.files.map((file) => {
                    return {
                        file: file,
                        content: "https://api.surveyjs.io/private/Surveys/getTempFile?name=" + data[file.name]
                    };
                })
            );
        })
        .catch((error) => {
            console.error("Error: ", error);
            options.callback([], [ "An error occurred during file upload." ]);
        });
});
async function deleteFile(fileURL) {
    try {
        const name = fileURL.split("=")[1];
        const apiUrl = `https://api.surveyjs.io/private/Surveys/deleteTempFile?name=${name}`;
        const response = await fetch(apiUrl, { method: "DELETE" });

        if (response.status === 200) {
            console.log(`File ${name} was deleted successfully`);
            return "success";
        } else {
            console.error(`Failed to delete file: ${name}`);
            return "error";
        }
    } catch (error) {
        console.error("Error while deleting file: ", error);
        return "error";
    }
}

survey.onClearFiles.add(async (_, options) => {
    if (!options.value || options.value.length === 0) {
        return options.callback("success");
    }

    const filesToDelete = options.fileName
        ? options.value.filter((item) => item.name === options.fileName)
        : options.value;

    if (filesToDelete.length === 0) {
        console.error(`File with name ${options.fileName} is not found`);
        return options.callback("error");
    }

    const results = await Promise.all(
        filesToDelete.map((file) => deleteFile(file.content))
    );

    if (results.every((res) => res === "success")) {
        options.callback("success");
    } else {
        options.callback("error");
    }
});

survey.render(document.getElementById("surveyElement"));
```

### `src/json.js`

```js
export const json = {
  "elements": [
    {
      "type": "file",
      "title": "Please upload your files",
      "name": "files",
      "storeDataAsText": false,
      "allowMultiple": true,
      "showPreview": false,
      "maxSize": 102400
    }
  ]
};
```

### `src/theme.js`

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

### `package.json`

```json
{
  "dependencies": {
    "babel": "latest",
    "survey-core": "latest",
    "survey-js-ui": "latest"
  }
}
```

## Other Frameworks

- [Angular](https://surveyjs.io/form-library/examples/custom-file-previews/angular.md)
- [React](https://surveyjs.io/form-library/examples/custom-file-previews/reactjs.md)
- [Vue 3](https://surveyjs.io/form-library/examples/custom-file-previews/vue3js.md)
- [jQuery](https://surveyjs.io/form-library/examples/custom-file-previews/jquery.md)
