Feature: Advanced Interactive Table Plugin
Date: 2025-12-11
Audience: Developers integrating the plugin with YASGUI
This guide demonstrates how to integrate the advanced table plugin with YASGUI to render SPARQL SELECT results as an interactive table with search, sort, resize, and export capabilities.
- YASGUI: Version 4.x or higher
- Browser: Chrome, Firefox, Safari, or Edge (latest 2 versions)
- Build Tool: esbuild (used internally), or any module bundler with ES6 support
- Node.js: 16+ (for development)
npm install @yasgui/table-plugin<script src="https://unpkg.com/@matdata/yasgui-table-plugin/dist/table-plugin.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@matdata/yasgui-table-plugin/dist/table-plugin.min.css">import Yasgui from '@yasgui/yasgui';
import TablePlugin from '@yasgui/table-plugin';
import '@yasgui/yasgui/build/yasgui.min.css';
import '@yasgui/table-plugin/dist/table-plugin.min.css';
// Register plugin with YASGUI
Yasgui.Yasr.plugins.table = TablePlugin;
// Initialize YASGUI
const yasgui = new Yasgui(document.getElementById('yasgui'), {
yasqe: {
value: `PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?person ?name ?age
WHERE {
?person foaf:name ?name ;
foaf:age ?age .
}
LIMIT 100`
},
yasr: {
// Set table as default plugin
defaultPlugin: 'table'
}
});Result: YASGUI renders with table plugin as default for SELECT queries.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>YASGUI with Table Plugin</title>
<!-- YASGUI styles -->
<link rel="stylesheet" href="https://unpkg.com/@yasgui/yasgui/build/yasgui.min.css">
<!-- Table plugin styles -->
<link rel="stylesheet" href="https://unpkg.com/@matdata/yasgui-table-plugin/dist/table-plugin.min.css">
<style>
#yasgui {
height: 100vh;
}
</style>
</head>
<body>
<div id="yasgui"></div>
<script type="module">
import Yasgui from 'https://unpkg.com/@yasgui/yasgui/build/yasgui.esm.js';
import TablePlugin from 'https://unpkg.com/@matdata/yasgui-table-plugin/dist/table-plugin.esm.js';
Yasgui.Yasr.plugins.table = TablePlugin;
const yasgui = new Yasgui(document.getElementById('yasgui'), {
yasr: { defaultPlugin: 'table' }
});
</script>
</body>
</html>const yasgui = new Yasgui(document.getElementById('yasgui'), {
yasr: {
defaultPlugin: 'table',
pluginConfig: {
table: {
displayConfig: {
uriDisplayMode: 'abbreviated', // Show prefixed URIs
showDatatypes: false, // Hide datatype annotations
ellipsisMode: true // Truncate long content
}
}
}
}
});Effect:
- URIs display as
foaf:Personinstead ofhttp://xmlns.com/foaf/0.1/Person - Literals show
42instead of42 (xsd:integer) - Long strings truncate with "…" (click to expand)
const yasgui = new Yasgui(document.getElementById('yasgui'), {
yasr: {
defaultPlugin: 'table',
pluginConfig: {
table: {
themeIntegration: true, // Use YASGUI theme colors
tabulatorOptions: {
layout: 'fitColumns', // Fit columns to container width
height: '600px' // Fixed height
}
}
}
}
});Effect: Table colors match YASGUI light/dark theme automatically.
const yasgui = new Yasgui(document.getElementById('yasgui'), {
yasr: {
defaultPlugin: 'table',
pluginConfig: {
table: {
tabulatorOptions: {
renderVertical: 'virtual', // Enable virtual scrolling
virtualDomBuffer: 500, // Larger render buffer
placeholder: 'Loading...' // Show during render
}
}
}
}
});Effect: Smooth scrolling for 10,000+ row datasets.
const yasgui = new Yasgui(document.getElementById('yasgui'), {
yasr: {
defaultPlugin: 'table',
pluginConfig: {
table: {
exportFormat: 'csv', // Default to CSV instead of TSV
displayConfig: {
uriDisplayMode: 'full' // Export full URIs
}
}
}
}
});Effect: Download button generates CSV files with full URIs.
const yasgui = new Yasgui(document.getElementById('yasgui'));
// Get active YASR instance
const yasr = yasgui.getTab().yasr;
// Get table plugin instance (after query execution)
yasr.on('drawn', () => {
const tablePlugin = yasr.plugins['table'];
if (tablePlugin && yasr.activePlugin === 'table') {
console.log('Table plugin active');
console.log('Current config:', tablePlugin.getConfig());
}
});const yasr = yasgui.getTab().yasr;
yasr.on('drawn', () => {
const tablePlugin = yasr.plugins['table'];
// Toggle URI display mode
document.getElementById('toggleURI').addEventListener('click', () => {
const currentMode = tablePlugin.getConfig().displayConfig.uriDisplayMode;
const newMode = currentMode === 'full' ? 'abbreviated' : 'full';
tablePlugin.updateConfig({
displayConfig: { uriDisplayMode: newMode }
});
});
});yasr.on('drawn', () => {
const tablePlugin = yasr.plugins['table'];
// Log search activity
tablePlugin.on('search', (e) => {
console.log(`Search: "${e.searchTerm}" - ${e.matchCount} matches`);
});
// Track cell clicks
tablePlugin.on('cellClick', (e) => {
console.log('Clicked:', e.value);
});
// Monitor copy operations
tablePlugin.on('copy', (e) => {
if (e.success) {
console.log(`Copied ${e.rowCount} rows as ${e.format}`);
}
});
});const yasgui = new Yasgui(document.getElementById('yasgui'), {
yasqe: {
value: `PREFIX dbr: <http://dbpedia.org/resource/>
PREFIX dbo: <http://dbpedia.org/ontology/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?city ?name ?population ?country
WHERE {
?city a dbo:City ;
foaf:name ?name ;
dbo:populationTotal ?population ;
dbo:country ?country .
FILTER(?population > 1000000)
}
ORDER BY DESC(?population)
LIMIT 100`
},
yasr: {
defaultPlugin: 'table',
pluginConfig: {
table: {
displayConfig: {
uriDisplayMode: 'abbreviated',
showDatatypes: false,
ellipsisMode: false
},
prefixMap: {
dbr: 'http://dbpedia.org/resource/',
dbo: 'http://dbpedia.org/ontology/',
foaf: 'http://xmlns.com/foaf/0.1/'
}
}
}
}
});Features Enabled:
- Abbreviated URIs (dbr:London instead of http://dbpedia.org/resource/London)
- Sortable columns (click "population" to sort)
- Searchable (search for "London")
- Copy to clipboard as Markdown, CSV, or TSV (tab-delimited)
- Tooltips showing full cell content on hover
- CSV download via YASR's download interface
const yasgui = new Yasgui(document.getElementById('yasgui'), {
yasqe: {
value: `SELECT ?item ?itemLabel ?birth ?death
WHERE {
?item wdt:P31 wd:Q5 ; # instance of human
wdt:P106 wd:Q901 ; # occupation: scientist
wdt:P569 ?birth ; # date of birth
wdt:P570 ?death . # date of death
FILTER(YEAR(?birth) >= 1900 && YEAR(?birth) < 2000)
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?birth
LIMIT 100`,
sparql: {
endpoint: 'https://query.wikidata.org/sparql'
}
},
yasr: {
defaultPlugin: 'table',
pluginConfig: {
table: {
displayConfig: {
uriDisplayMode: 'abbreviated',
showDatatypes: true, // Show date datatypes
ellipsisMode: false
},
tabulatorOptions: {
layout: 'fitDataFill' // Fit to container
}
}
}
}
});Features Enabled:
- Date sorting (click "birth" column)
- Datatype visibility (xsd:date annotations)
- 100+ row virtual scrolling
const yasgui = new Yasgui(document.getElementById('yasgui'), {
yasqe: {
sparql: {
endpoint: 'https://api.example.com/sparql',
headers: {
'Authorization': 'Bearer YOUR_TOKEN_HERE'
}
}
},
yasr: {
defaultPlugin: 'table',
pluginConfig: {
table: {
persistenceKey: 'my-custom-endpoint-table', // Separate storage key
exportFormat: 'markdown', // Default to Markdown
displayConfig: {
uriDisplayMode: 'full', // Always show full URIs
showDatatypes: true,
ellipsisMode: true
}
}
}
}
});Features:
- Custom authentication headers
- Isolated localStorage (won't conflict with other instances)
- Markdown export format (also supports CSV and TSV)
- Full URI display
- Visual notifications for copy operations
// Register plugin with custom formatter
class CustomTablePlugin extends TablePlugin {
generateColumns(vars) {
const columns = super.generateColumns(vars);
// Custom formatter for "email" column
const emailColumn = columns.find(col => col.field === 'email');
if (emailColumn) {
emailColumn.formatter = (cell) => {
const email = cell.getValue().value;
return `<a href="mailto:${email}">${email}</a>`;
};
}
return columns;
}
}
Yasgui.Yasr.plugins.table = CustomTablePlugin;Effect: Email addresses become clickable mailto: links
// Custom search input outside YASGUI
const searchInput = document.getElementById('externalSearch');
const yasr = yasgui.getTab().yasr;
searchInput.addEventListener('input', debounce((e) => {
const tablePlugin = yasr.plugins['table'];
if (tablePlugin && yasr.activePlugin === 'table') {
tablePlugin.applyFilter(e.target.value);
}
}, 300));
function debounce(func, wait) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}Effect: External search input controls table filtering
yasr.on('drawn', () => {
const tablePlugin = yasr.plugins['table'];
// Track plugin usage
analytics.track('Table Plugin Loaded', {
rowCount: tablePlugin.table?.getDataCount(),
columnCount: tablePlugin.table?.getColumns().length
});
// Track search usage
tablePlugin.on('search', (e) => {
analytics.track('Table Search', {
term: e.searchTerm,
results: e.matchCount
});
});
// Track copy operations
tablePlugin.on('copy', (e) => {
analytics.track('Table Copy', {
format: e.format,
rows: e.rowCount,
success: e.success
});
});
});Symptom: Table plugin not appearing in YASR selector.
Solution:
// Check registration
console.log('Registered plugins:', Object.keys(Yasgui.Yasr.plugins));
// Ensure plugin is registered before YASGUI init
Yasgui.Yasr.plugins.table = TablePlugin;
const yasgui = new Yasgui(...);Symptom: Table appears unstyled or broken layout.
Solution:
<!-- Ensure CSS is loaded -->
<link rel="stylesheet" href="@matdata/yasgui-table-plugin/dist/table-plugin.min.css">
<!-- Check CSS loading order (YASGUI first, then plugin) -->
<link rel="stylesheet" href="@yasgui/yasgui/build/yasgui.min.css">
<link rel="stylesheet" href="@matdata/yasgui-table-plugin/dist/table-plugin.min.css">Symptom: Display settings reset on page reload.
Solution:
// Check localStorage availability
if (typeof localStorage === 'undefined') {
console.error('localStorage not available');
}
// Check persistence enabled
const config = tablePlugin.getConfig();
console.log('Persistence enabled:', config.persistenceEnabled);
// Use custom storage key for isolation
{
pluginConfig: {
table: {
persistenceKey: 'my-unique-key'
}
}
}Symptom: Table takes >2 seconds to render 10,000 rows.
Solution:
// Ensure virtual scrolling enabled
{
tabulatorOptions: {
renderVertical: 'virtual',
virtualDomBuffer: 300, // Reduce if memory-constrained
height: '600px' // Fixed height required for virtual scrolling
}
}
// Simplify formatters
{
displayConfig: {
ellipsisMode: true, // Faster rendering
showDatatypes: false // Fewer DOM nodes
}
}Symptom: Ctrl+C does not copy selection.
Solution:
// Check HTTPS context (Clipboard API requires secure context)
console.log('Secure context:', window.isSecureContext);
// Automatic fallback to execCommand on HTTP or when Clipboard API fails
if (!window.isSecureContext) {
console.warn('Clipboard API unavailable. Using legacy execCommand fallback.');
}
// Plugin automatically handles focus issues and fallbacks
// Visual notifications will indicate success or failure
// Check browser permissions
navigator.permissions.query({ name: 'clipboard-write' })
.then(result => {
console.log('Clipboard permission:', result.state);
});| Feature | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| Core table rendering | ✅ 90+ | ✅ 88+ | ✅ 14+ | ✅ 90+ |
| Virtual scrolling | ✅ 90+ | ✅ 88+ | ✅ 14+ | ✅ 90+ |
| Clipboard API | ✅ 90+ | ✅ 90+ | ✅ 13.1+ | ✅ 90+ |
| CSS Grid | ✅ 57+ | ✅ 52+ | ✅ 10.1+ | ✅ 16+ |
| localStorage | ✅ All | ✅ All | ✅ All | ✅ All |
Fallbacks:
- Clipboard API →
document.execCommand('copy')for HTTP contexts - CSS Grid → Flexbox fallback (automatic via PostCSS)
- Clone repository:
git clone https://github.com/yasgui/table-plugin.git - Install dependencies:
npm install - Run dev server:
npm run dev(opens demo at http://localhost:3000 with Vite) - Run tests:
npm test - Build:
npm run build(uses esbuild, outputs UMD and ESM todist/) - Watch mode:
npm run dev:build(esbuild watch mode for incremental builds)
- Full specification - Feature requirements and user stories
- Data model - SPARQL binding structures
- Plugin API - Complete API reference
- Configuration schema - All config options
- Event system - Event contracts
- Tabulator documentation - Underlying library
Full working examples: https://github.com/yasgui/table-plugin/tree/main/demo
- Issues: https://github.com/yasgui/table-plugin/issues
- Discussions: https://github.com/yasgui/table-plugin/discussions
- YASGUI Documentation: https://triply.cc/docs/yasgui
Quickstart Complete ✅
Plugin ready for integration with YASGUI/YASR ecosystem.