ai-chatbot
ai-chatbot copied to clipboard
I want to add icon for exporting to excel near copy icons to export data , How to code?
Now , I added markdown for supporting table and I want to add icon export to excel How to code?
Hi @angpao , did you find a solution?
To add an action, you can add it in the artifacts/text/client.tsx file
For example:
actions: [
{
icon: <FileDown size={18} />,
description: 'Download',
onClick: ({ content }) => {
const blob = new Blob([content], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'document.txt';
a.click();
URL.revokeObjectURL(url);
toast.success('Document downloaded!');
},
},
@angpao Were you able to fix this? I'm curious about it too.
solution: Added Excel export after table using xlsx.
npm install xlsx
- markdown.tsx
table: ({ node, children, ...props }) => {
return <TableWithExport {...props}>{children}</TableWithExport>
},
- table-with-export.tsx
"use client"
import { type ReactNode, useRef } from "react"
import { Button } from "@/components/ui/button"
import { Download } from "lucide-react"
import { exportTableToExcel } from "@/utils/excel-export"
interface TableWithExportProps {
children: ReactNode
className?: string
}
export function TableWithExport({ children, className, ...props }: TableWithExportProps) {
const tableRef = useRef<HTMLTableElement>(null)
const handleExport = () => {
if (!tableRef.current) return
// Extract table data
const rows = Array.from(tableRef.current.querySelectorAll("tr"))
const tableData = rows.map((row) =>
Array.from(row.querySelectorAll("th, td")).map((cell) => cell.textContent || ""),
)
// Determine filename from table context
let filename = "table-export"
// Try to get filename from table caption if it exists
const caption = tableRef.current.querySelector("caption")
if (caption && caption.textContent) {
filename = caption.textContent.trim()
}
// Otherwise, try to get filename from first row (headers)
else if (tableData.length > 0 && tableData[0].length > 0) {
// Join the header row with hyphens
filename = tableData[0].join("-")
}
// Look for a preceding heading as an alternative
if (filename === "table-export") {
// Get the table's parent element
const tableParent = tableRef.current.parentElement
if (tableParent) {
// Look for the closest preceding heading
let currentElement = tableParent.previousElementSibling
while (currentElement) {
if (/^H[1-6]$/.test(currentElement.tagName)) {
filename = currentElement.textContent?.trim() || filename
break
}
currentElement = currentElement.previousElementSibling
}
}
}
// Sanitize filename (remove invalid characters)
filename = filename
.replace(/[\\/:*?"<>|]/g, "-") // Replace invalid filename chars
.replace(/\s+/g, "-") // Replace spaces with hyphens
.substring(0, 50) // Limit length
// Export to Excel
exportTableToExcel(tableData, filename)
}
return (
<div className="relative mb-6">
<div className="overflow-x-auto rounded-lg border border-zinc-200 dark:border-zinc-700">
<table ref={tableRef} className={`w-full text-sm ${className || ""}`} {...props}>
{children}
</table>
</div>
<div className="flex justify-end mt-2">
<Button onClick={handleExport} size="sm" variant="outline" className="flex items-center gap-1 text-xs">
<Download className="h-3 w-3" />
Export to Excel
</Button>
</div>
</div>
)
}
- excel-export.ts
import * as XLSX from "xlsx"
export function exportTableToExcel(tableData: string[][], filename = "table-export") {
// Create a worksheet from the table data
const ws = XLSX.utils.aoa_to_sheet(tableData)
// Create a workbook with the worksheet
const wb = XLSX.utils.book_new()
XLSX.utils.book_append_sheet(wb, ws, "Sheet1")
// Generate the Excel file as a binary string
const excelBuffer = XLSX.write(wb, { bookType: "xlsx", type: "array" })
// Convert to Blob
const blob = new Blob([excelBuffer], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
})
// Create download link
const url = URL.createObjectURL(blob)
// Create temporary anchor element to trigger download
const a = document.createElement("a")
a.href = url
a.download = `${filename}.xlsx`
document.body.appendChild(a)
a.click()
// Clean up
setTimeout(() => {
document.body.removeChild(a)
URL.revokeObjectURL(url)
}, 0)
}