New to Kendo UI for jQueryStart a free 30-day trial

Upload and Download Files in the Chat

Updated on Jun 17, 2026

Environment

ProductProgress® Kendo UI® Chat for jQuery

Description

How can I allow users to attach files to Chat messages, download them, and view file details through a popup window in the Kendo UI for jQuery Chat?

Solution

The following approach demonstrates how to:

  1. Enable file attachments with allowed extension restrictions using the fileAttachment option.
  2. Define custom file actions (Download and View Details) through the fileActions configuration.
  3. Upload files to a server endpoint via AJAX inside the sendMessage event handler.
  4. Handle file downloads in the download event using kendo.saveAs.
  5. Show file metadata and image previews inside a Kendo UI Window when the custom "View Details" action is triggered through the fileMenuAction event.

Configure the Chat with File Attachments and Actions

The following example initializes the Chat with the fileAttachment and fileActions options, wires up the sendMessage, fileMenuAction, and download events, and opens a Kendo UI Window to display file metadata when a user selects View Details.

HTML
<div class="k-d-flex k-justify-content-center">
    <div id="chat"></div>
</div>

<div id="fileDetailsWindow"></div>

<script>
    var currentUser = {
        id: 1,
        name: "John Doe",
        iconUrl: "https://demos.telerik.com/kendo-ui/content/web/Customers/RICSU.jpg",
        iconAltText: "John's profile picture"
    };

    var imageExtensions = [".ai", ".dds", ".heic", ".jpe", ".jfif", ".jif", ".jp2", ".jps",
        ".eps", ".bmp", ".gif", ".jpeg", ".jpg", ".png", ".ps", ".psd", ".svg", ".svgz", ".tif", ".tiff"];

    function isDisplayableImage(extension) {
        if (!extension) return false;
        var ext = extension.toLowerCase();
        if (ext.charAt(0) !== ".") ext = "." + ext;
        var displayable = [".bmp", ".gif", ".jpeg", ".jpg", ".png", ".svg", ".svgz"];
        return displayable.indexOf(ext) > -1;
    }

    function formatFileSize(bytes) {
        if (bytes === 0) return "0 Bytes";
        var sizes = ["Bytes", "KB", "MB", "GB"];
        var i = Math.floor(Math.log(bytes) / Math.log(1024));
        return parseFloat((bytes / Math.pow(1024, i)).toFixed(2)) + " " + sizes[i];
    }

    function uploadFilesToServer(files) {
        return new Promise(function (resolve, reject) {
            var formData = new FormData();
            files.forEach(function (file) {
                formData.append("files", file.rawFile);
            });

            $.ajax({
                url: "../chat/savefiles",
                type: "POST",
                data: formData,
                processData: false,
                contentType: false,
                success: function (response) {
                    if (response.success) {
                        resolve(response.files);
                    } else {
                        reject(response.message || "Upload failed");
                    }
                },
                error: function (xhr, status, error) {
                    reject(error);
                }
            });
        });
    }

    $(document).ready(function () {
        $("#fileDetailsWindow").kendoWindow({
            title: "File Details",
            visible: false,
            modal: true,
            width: 420,
            actions: ["Close"]
        });

        $("#chat").kendoChat({
            height: "600px",
            width: "400px",
            authorId: "1",
            fileAttachment: {
                restrictions: {
                    allowedExtensions: [".jpg", ".png", ".pdf", ".xlsx", ".docx", ".txt"]
                }
            },
            fileActions: [
                { name: "download", text: "Download", icon: "download" },
                { name: "viewdetails", text: "View Details", icon: "eye" }
            ],
            dataSource: {
                data: [
                    {
                        id: "1",
                        authorId: "2",
                        authorName: "Peter Smith",
                        authorImageUrl: "https://demos.telerik.com/kendo-ui/content/web/Customers/GOURL.jpg",
                        authorImageAltText: "Peter's profile picture",
                        text: "Use the paperclip button in the message input area to attach files, and the file action menu to download or delete them.",
                        timestamp: new Date()
                    },
                    {
                        id: "2",
                        authorId: "2",
                        authorName: "Peter Smith",
                        authorImageUrl: "https://demos.telerik.com/kendo-ui/content/web/Customers/GOURL.jpg",
                        authorImageAltText: "Peter's profile picture",
                        text: "Go ahead and upload your first file. Once uploaded, I will receive it with a download link so both of us can access it.",
                        timestamp: new Date()
                    }
                ]
            },
            sendMessage: function (e) {
                var chat = e.sender;

                e.message.authorId = currentUser.id;
                e.message.authorName = currentUser.name;
                e.message.authorImageUrl = currentUser.iconUrl;
                e.message.authorImageAltText = currentUser.iconAltText;

                if (e.message.files && e.message.files.length > 0) {
                    var files = e.message.files;

                    uploadFilesToServer(files).then(function (results) {
                        var peerFiles = results.map(function (result) {
                            return {
                                name: result.name,
                                size: result.size,
                                extension: result.extension,
                                url: result.url
                            };
                        });

                        var fileDetails = peerFiles.map(function (f) {
                            return "Name: " + f.name +
                                ", Size: " + formatFileSize(f.size) +
                                ", Type: " + f.extension;
                        }).join("\n\n");

                        chat.postMessage({
                            authorId: 2,
                            authorName: "Peter Smith",
                            authorImageUrl: "https://demos.telerik.com/kendo-ui/content/web/Customers/GOURL.jpg",
                            authorImageAltText: "Peter's profile picture",
                            text: "Thanks for uploading " + files.length + " file(s). I can now access and download them!\n\nFile details:\n" + fileDetails,
                            files: peerFiles,
                            timestamp: new Date()
                        });
                    }).catch(function (error) {
                        console.error("File upload failed:", error);
                        chat.postMessage({
                            authorId: 2,
                            authorName: "Peter Smith",
                            authorImageUrl: "https://demos.telerik.com/kendo-ui/content/web/Customers/GOURL.jpg",
                            authorImageAltText: "Peter's profile picture",
                            text: "Sorry, there was an error uploading the file(s). Please try again.",
                            timestamp: new Date()
                        });
                    });
                } else {
                    setTimeout(function () {
                        chat.postMessage({
                            authorId: 2,
                            authorName: "Peter Smith",
                            authorImageUrl: "https://demos.telerik.com/kendo-ui/content/web/Customers/GOURL.jpg",
                            authorImageAltText: "Peter's profile picture",
                            text: "Got it! You can also attach files using the file button in the message input area.",
                            timestamp: new Date()
                        });
                    }, 500);
                }
            },
            fileMenuAction: function (e) {
                if (e.type === "viewdetails") {
                    showFileDetails(e.file);
                }
            },
            download: function (e) {
                if (!e.files || e.files.length === 0) {
                    return;
                }

                e.files.forEach(function (file) {
                    if (file.url) {
                        // Download from server URL
                        fetch(file.url)
                            .then(function (response) {
                                if (!response.ok) {
                                    throw new Error("Download failed");
                                }
                                return response.blob();
                            })
                            .then(function (blob) {
                                kendo.saveAs({
                                    dataURI: blob,
                                    fileName: file.name
                                });
                            })
                            .catch(function (err) {
                                console.error("Download error:", err);
                                kendo.alert("File is not available for download: " + file.name);
                            });
                    } else if (file.rawFile) {
                        // Fallback for files still in browser memory
                        kendo.saveAs({
                            dataURI: file.rawFile,
                            fileName: file.name
                        });
                    } else {
                        kendo.alert("File is not available for download: " + file.name);
                    }
                });
            }
        });
    });

    function showFileDetails(file) {
        var fileUrl = file.url;
        var extension = file.extension || "";
        var canPreview = isDisplayableImage(extension) && fileUrl;
        var iconName = kendo.getFileGroup(extension, true);
        var contentHtml = "";

        if (canPreview) {
            contentHtml += '<div style="text-align: center; margin-bottom: 16px;">' +
                '<img src="' + kendo.htmlEncode(fileUrl) + '" alt="' + kendo.htmlEncode(file.name) + '" style="max-width: 100%; max-height: 200px; border-radius: 4px;" />' +
                '</div>';
        } else {
            contentHtml += '<div style="text-align: center; margin-bottom: 16px;">' +
                kendo.ui.icon({ icon: iconName, size: "xxxlarge" }) +
                '</div>';
        }

        contentHtml += '<table class="k-table" style="width: 100%; border-collapse: collapse;">' +
            '<tbody>' +
            '<tr><td style="padding: 8px; font-weight: bold; width: 100px;">Name</td><td style="padding: 8px;">' + kendo.htmlEncode(file.name || "N/A") + '</td></tr>' +
            '<tr><td style="padding: 8px; font-weight: bold;">Size</td><td style="padding: 8px;">' + formatFileSize(file.size || 0) + '</td></tr>' +
            '<tr><td style="padding: 8px; font-weight: bold;">Type</td><td style="padding: 8px;">' + kendo.htmlEncode(extension || "Unknown") + '</td></tr>' +
            '<tr><td style="padding: 8px; font-weight: bold;">Category</td><td style="padding: 8px;">' + kendo.htmlEncode(kendo.getFileGroup(extension, false) || "file") + '</td></tr>' +
            '</tbody></table>';

        var wnd = $("#fileDetailsWindow").data("kendoWindow");
        wnd.content(contentHtml);
        wnd.title("File Details - " + (file.name || "Unknown"));
        wnd.center().open();
    }
</script>

<style>
    .k-chat {
        min-width: 300px !important;
    }
</style>

For a runnable example, refer to the Chat Access Files demo.

See Also