Enterprise Component — The SpreadsheetViewer component is available to Reducto enterprise customers.
Contact [email protected] to get access.
Overview
The SpreadsheetViewer component provides a powerful, read-only Excel spreadsheet viewer with support for bounding box overlays. It’s designed to visualize Reducto extraction results directly on your spreadsheet documents.
Excel Support View .xlsx and .xls files with full sheet navigation
Bounding Boxes Overlay extraction results with clickable, colored regions
Zero Tailwind CSS Variables for easy theming without Tailwind dependency
TypeScript Full type definitions included for excellent DX
Installation
Configure npm registry
Create or update your project’s .npmrc file to authenticate with GitHub Packages: @reductoai-collab:registry =https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken = ${ REDUCTO_NPM_TOKEN }
Never commit your token directly to .npmrc. Use an environment variable as shown above.
Set your authentication token
Reducto will provide you with an access token. Set it as an environment variable: macOS / Linux
Windows
CI/CD
Add to your shell profile (~/.bashrc, ~/.zshrc, etc.): export REDUCTO_NPM_TOKEN = "your-token-from-reducto"
Then reload your shell: source ~/.zshrc # or ~/.bashrc
Set as a system environment variable: [ System.Environment ]::SetEnvironmentVariable( 'REDUCTO_NPM_TOKEN' , 'your-token-from-reducto' , 'User' )
Restart your terminal after setting. Add REDUCTO_NPM_TOKEN as a secret in your CI environment: env :
REDUCTO_NPM_TOKEN : ${{ secrets.REDUCTO_NPM_TOKEN }}
variables :
REDUCTO_NPM_TOKEN : $REDUCTO_NPM_TOKEN
Install the package
npm install @reductoai-collab/components
yarn add @reductoai-collab/components
pnpm add @reductoai-collab/components
Import the styles
Import the CSS file in your application’s entry point: import '@reductoai-collab/components/styles/spreadsheet-viewer.css' ;
Quick Start
Here’s a minimal example to get you started:
import { SpreadsheetViewer } from '@reductoai-collab/components' ;
import '@reductoai-collab/components/styles/spreadsheet-viewer.css' ;
function App () {
return (
< div style = { { height: '600px' , width: '100%' } } >
< SpreadsheetViewer
url = "https://example.com/spreadsheet.xlsx"
onLoad = { ( metadata ) => {
console . log ( `Loaded ${ metadata . sheetCount } sheets` );
} }
onError = { ( error ) => {
console . error ( `Error: ${ error . message } ` );
} }
/>
</ div >
);
}
The SpreadsheetViewer requires a container with defined dimensions. Always wrap it in a parent element with explicit height and width.
Usage Examples
Basic Viewer
Display a spreadsheet without any overlays:
import { SpreadsheetViewer } from '@reductoai-collab/components' ;
function BasicViewer () {
return (
< div style = { { height: '600px' , width: '100%' } } >
< SpreadsheetViewer
url = "/documents/financial-report.xlsx"
onLoad = { ( metadata ) => {
console . log ( 'Sheet names:' , metadata . sheetNames );
} }
/>
</ div >
);
}
With Bounding Boxes
Highlight specific regions of the spreadsheet with colored bounding boxes:
import { SpreadsheetViewer , type BoundingBox } from '@reductoai-collab/components' ;
function ViewerWithBboxes () {
const bboxes : BoundingBox [] = [
{
id: 'header-row' ,
page: 1 , // Sheet number (1-indexed)
top: 1 , // Starting row
left: 1 , // Starting column (A = 1)
width: 5 , // Number of columns
height: 1 , // Number of rows
color: 'blue' ,
label: 'Header' ,
},
{
id: 'data-table' ,
page: 1 ,
top: 2 ,
left: 1 ,
width: 5 ,
height: 10 ,
color: 'green' ,
label: 'Sales Data' ,
metadata: {
tableId: 'tbl-001' ,
confidence: 0.95 ,
},
},
];
return (
< div style = { { height: '600px' , width: '100%' } } >
< SpreadsheetViewer
url = "/documents/sales-data.xlsx"
bboxes = { bboxes }
onBboxClick = { ( bbox ) => {
console . log ( 'Clicked:' , bbox . id );
console . log ( 'Custom data:' , bbox . metadata );
} }
/>
</ div >
);
}
Integrating with Reducto API Results
Convert Reducto extraction results to bounding boxes:
import { useState } from 'react' ;
import { SpreadsheetViewer , type BoundingBox } from '@reductoai-collab/components' ;
interface ReductoBlock {
id : string ;
type : 'table' | 'text' | 'key_value' ;
bbox : {
page : number ;
top : number ;
left : number ;
width : number ;
height : number ;
};
content : string ;
}
interface ExtractionResult {
blocks : ReductoBlock [];
}
function ReductoViewer ({
documentUrl ,
extractionResult ,
} : {
documentUrl : string ;
extractionResult : ExtractionResult ;
}) {
const [ selectedBlock , setSelectedBlock ] = useState < ReductoBlock | null >( null );
// Map block types to colors
const colorMap : Record < string , BoundingBox [ 'color' ]> = {
table: 'blue' ,
text: 'green' ,
key_value: 'purple' ,
};
// Convert Reducto blocks to bounding boxes
const bboxes : BoundingBox [] = extractionResult . blocks . map (( block ) => ({
id: block . id ,
page: block . bbox . page ,
top: block . bbox . top ,
left: block . bbox . left ,
width: block . bbox . width ,
height: block . bbox . height ,
color: colorMap [ block . type ] ?? 'gray' ,
label: block . type ,
metadata: {
blockId: block . id ,
type: block . type ,
content: block . content ,
},
}));
return (
< div style = { { display: 'flex' , height: '600px' } } >
{ /* Viewer */ }
< div style = { { flex: 1 } } >
< SpreadsheetViewer
url = { documentUrl }
bboxes = { bboxes }
onBboxClick = { ( bbox ) => {
const block = extractionResult . blocks . find (
( b ) => b . id === bbox . metadata ?. blockId
);
setSelectedBlock ( block ?? null );
} }
/>
</ div >
{ /* Details Panel */ }
< div style = { { width: '300px' , padding: '16px' , borderLeft: '1px solid #e5e7eb' } } >
< h3 > Selected Block </ h3 >
{ selectedBlock ? (
< div >
< p >< strong > Type: </ strong > { selectedBlock . type } </ p >
< p >< strong > Content: </ strong ></ p >
< pre style = { { whiteSpace: 'pre-wrap' , fontSize: '12px' } } >
{ selectedBlock . content }
</ pre >
</ div >
) : (
< p style = { { color: '#6b7280' } } > Click a bounding box to see details </ p >
) }
</ div >
</ div >
);
}
Custom Styling with CSS Variables
Override the default styles using CSS variables:
:root {
/* Container */
--sv-background : #1a1a2e ;
--sv-border-color : #2d2d44 ;
--sv-border-radius : 8 px ;
/* Tabs */
--sv-tab-background : #2d2d44 ;
--sv-tab-background-active : #3d3d5c ;
--sv-tab-color : #a0a0b0 ;
--sv-tab-color-active : #ffffff ;
/* Grid */
--sv-header-background : #2d2d44 ;
--sv-header-color : #ffffff ;
--sv-cell-background : #1a1a2e ;
--sv-cell-color : #e0e0e0 ;
--sv-cell-border-color : #2d2d44 ;
/* Bounding boxes */
--sv-bbox-border-width : 2 px ;
--sv-bbox-opacity : 0.15 ;
--sv-bbox-opacity-hover : 0.25 ;
}
All available CSS variables
:root {
/* Container */
--sv-font-family : system-ui , -apple-system , sans-serif ;
--sv-background : #ffffff ;
--sv-border-color : #e5e7eb ;
--sv-border-radius : 4 px ;
/* Tabs */
--sv-tab-height : 36 px ;
--sv-tab-padding : 0 16 px ;
--sv-tab-background : #f9fafb ;
--sv-tab-background-hover : #f3f4f6 ;
--sv-tab-background-active : #ffffff ;
--sv-tab-color : #6b7280 ;
--sv-tab-color-active : #111827 ;
--sv-tab-font-size : 13 px ;
--sv-tab-font-weight : 500 ;
/* Grid */
--sv-header-background : #f9fafb ;
--sv-header-color : #374151 ;
--sv-header-font-size : 12 px ;
--sv-header-font-weight : 600 ;
--sv-cell-background : #ffffff ;
--sv-cell-color : #111827 ;
--sv-cell-font-size : 13 px ;
--sv-cell-padding : 4 px 8 px ;
--sv-cell-border-color : #e5e7eb ;
--sv-cell-min-width : 80 px ;
--sv-cell-height : 24 px ;
--sv-row-header-width : 50 px ;
/* Selection */
--sv-selection-background : rgba ( 59 , 130 , 246 , 0.1 );
--sv-selection-border-color : #3b82f6 ;
/* Scrollbar */
--sv-scrollbar-width : 8 px ;
--sv-scrollbar-track : #f1f1f1 ;
--sv-scrollbar-thumb : #c1c1c1 ;
--sv-scrollbar-thumb-hover : #a1a1a1 ;
/* Bounding boxes */
--sv-bbox-border-width : 2 px ;
--sv-bbox-opacity : 0.1 ;
--sv-bbox-opacity-hover : 0.2 ;
/* Loading & Error states */
--sv-loading-color : #6b7280 ;
--sv-error-color : #dc2626 ;
--sv-error-background : #fef2f2 ;
}
API Reference
SpreadsheetViewer Props
URL to the Excel file (.xlsx or .xls). Can be a relative path, absolute URL, or blob URL.
Array of bounding boxes to overlay on the spreadsheet.
onLoad
(metadata: WorkbookMetadata) => void
Callback fired when the workbook is successfully loaded.
onError
(error: SpreadsheetError) => void
Callback fired when an error occurs loading or parsing the file.
onBboxClick
(bbox: BoundingBox) => void
Callback fired when a bounding box is clicked.
Additional CSS class name for the container element.
Inline styles for the container element.
BoundingBox Type
interface BoundingBox {
id : string ; // Unique identifier
page : number ; // Sheet number (1-indexed)
top : number ; // Starting row (1-indexed)
left : number ; // Starting column (1-indexed, A=1)
width : number ; // Number of columns
height : number ; // Number of rows
color ?: BoundingBoxColor ; // Box color (default: 'blue')
label ?: string ; // Optional label text
metadata ?: Record < string , unknown >; // Custom data
}
type BoundingBoxColor =
| 'blue' | 'green' | 'red' | 'yellow'
| 'purple' | 'orange' | 'pink' | 'gray' ;
interface WorkbookMetadata {
sheetCount : number ; // Total number of sheets
sheetNames : string []; // Array of sheet names
activeSheet : number ; // Currently active sheet index
}
SpreadsheetError Type
interface SpreadsheetError {
code : 'FETCH_ERROR' | 'PARSE_ERROR' | 'INVALID_FORMAT' ;
message : string ;
originalError ?: Error ;
}
Troubleshooting
Package not found during installation
Ensure your .npmrc is configured correctly and the REDUCTO_NPM_TOKEN environment variable is set: echo $REDUCTO_NPM_TOKEN # Should print your token
If using a monorepo, place the .npmrc in the root directory.
CORS errors when loading spreadsheets
If loading files from a different domain, ensure the server sends appropriate CORS headers: Access-Control-Allow-Origin: *
Alternatively, proxy the request through your own backend or use blob URLs.
Bounding boxes not appearing
Verify that:
The page property matches the sheet number (1-indexed)
The top and left values are within the sheet bounds
You’ve imported the CSS file
Make sure you import the CSS file in your app’s entry point: import '@reductoai-collab/components/styles/spreadsheet-viewer.css' ;
If using CSS modules or scoped styles, ensure the import is global.
Support
Get Access Contact [email protected] to get access to @reductoai-collab/components and receive your authentication token.
For technical support, reach out to your Reducto account representative or email [email protected] .