logoSemaphor

Troubleshooting

Common issues and solutions when building custom visuals

"Element type is invalid" Error

This is the most common error. It occurs when component names don't match across files.

Symptom:

Error: Element type is invalid. Received a promise that resolves to: undefined.
Lazy element type must resolve to a class or function.

Cause: Name mismatch between configuration and exports.

Example of the problem:

// components.config.ts
{ component: 'RevenueChart' }  // Expects 'RevenueChart'
 
// index.ts
export { RevenueChart } from '...';  // Exports 'RevenueChart'
 
// revenue-chart.tsx
export function MyRevenueChart() { }  // Wrong! Exports 'MyRevenueChart'

Fix: Ensure all three names match exactly:

// components.config.ts
{ component: 'RevenueChart' }
 
// index.ts
export { RevenueChart } from './semaphor-components/revenue-chart/revenue-chart';
 
// revenue-chart.tsx
export function RevenueChart() { }  // Correct!

Checklist when renaming components:

  • Function name in .tsx file
  • Export in index.ts
  • component field in components.config.ts
  • Key in sample-data-registry.ts
  • Run npm run build

Component Not Appearing in Semaphor

  1. Verify export: Is the component exported in index.ts?
  2. Check config: Is it registered in components.config.ts?
  3. Verify names match: Does component exactly match the exported function name?
  4. Rebuild and republish: npm run build && semaphor publish
  5. Hard refresh: Clear browser cache and reload Semaphor

Data is Empty

  1. Configure data source: Ensure the card has a data source in Semaphor
  2. Check column names: Verify you're accessing correct column names
  3. Add debugging: console.log('data:', data) to inspect
  4. Handle empty state: Always check if (!data || data.length === 0)

Debug pattern:

export function MyVisual({ data }: SingleInputVisualProps) {
  // Add this temporarily to debug
  console.log('Data received:', data);
  console.log('Columns:', data?.[0] ? Object.keys(data[0]) : 'no data');
 
  if (!data?.length) {
    return <div>No data available</div>;
  }
 
  // ...rest of component
}

Inline Filters Not Showing

  1. Default to []: Ensure inlineFilters = [] in props destructuring
  2. Check conditional: Use inlineFilters.length > 0 before rendering
  3. Configure in Semaphor: Inline filters must be added to the card in Semaphor's visual editor

Correct pattern:

export function MyVisual({
  data,
  inlineFilters = []  // Always provide default
}: SingleInputVisualProps) {
  return (
    <div>
      {inlineFilters.length > 0 && (
        <div className="flex gap-2 p-3 bg-muted/30 rounded-lg">
          {inlineFilters}
        </div>
      )}
      {/* ...rest of visual */}
    </div>
  );
}

Styling Issues

CSS Not Loading

  1. Import CSS: Verify ../index.css is imported in index.ts
  2. Check build output: Ensure dist/style.css exists after build

Tailwind Classes Not Working

All Tailwind utilities are available. If classes aren't applying:

  1. Check for typos in class names
  2. Ensure you're not overriding with inline styles
  3. Check CSS specificity issues

Theme Colors Not Applying

  1. Use theme prop: Access colors via theme?.colors
  2. Provide fallbacks: Always have fallback colors
const primaryColor = theme?.colors?.[0] || '#3b82f6';
const isDarkMode = theme?.mode === 'dark';

Dark Mode Issues

Use conditional styling based on theme?.mode:

<div className={theme?.mode === 'dark' ? 'bg-gray-900 text-white' : 'bg-white text-gray-900'}>
  ...
</div>

Or use Tailwind's dark mode classes (if configured):

<div className="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
  ...
</div>

Showcase Not Showing Component

  1. Check registry: Is the component registered in sample-data-registry.ts?
  2. Verify key: The registry key must match the component name exactly
  3. Check data file: Ensure .data.ts exports sampleData

Registry format:

// sample-data-registry.ts
import * as myVisualData from '../components/semaphor-components/my-visual/my-visual.data';
 
export const sampleDataRegistry = {
  MyVisual: myVisualData,  // Key must match component name
};

Data file format:

// my-visual.data.ts
export const sampleData = [
  { column1: 'value1', column2: 100 },
  { column1: 'value2', column2: 200 },
];
 
export const sampleSettings = {
  title: 'My Visual',
};
 
export const sampleTheme = {
  colors: ['#3b82f6', '#10b981'],
  mode: 'light' as const,
};

Build Errors

Clean Rebuild

rm -rf dist node_modules
npm install
npm run build

TypeScript Errors

Run type checking independently:

npx tsc --noEmit

Missing Dependencies

If you're using external libraries:

npm install [library-name]

Then verify it's included in the bundle by checking dist/index.js size.


Publishing Issues

"Unauthorized" Error

  1. Verify your project credentials in semaphor.json
  2. Re-run semaphor init to update credentials
  3. Check that your Semaphor project ID matches

Plugin Not Updating

  1. Increment version in package.json
  2. Rebuild: npm run build
  3. Republish: semaphor publish
  4. Hard refresh Semaphor dashboard (Ctrl+Shift+R)

Manifest Not Generated

The manifest is generated from components.config.ts during build. Ensure:

  1. components.config.ts has valid syntax
  2. All registered components are exported in index.ts
  3. Build completes without errors

Performance Issues

Component Re-rendering Too Often

Use useMemo for expensive calculations:

const processedData = useMemo(() => {
  return data.map(row => /* expensive transformation */);
}, [data]);

Large Dataset Handling

For datasets over 1000 rows:

  1. Consider virtualization (react-virtual, react-window)
  2. Paginate on the server side
  3. Aggregate data in SQL before sending to the visual

Multi-Input Visual Issues

Data Not Loading for All Slots

  1. Check that all slot cards have valid data sources
  2. Verify dataInputCardIds mapping is correct
  3. Ensure the source cards exist on the dashboard

CardMetadata Array Empty

Multi-input visuals receive an array of metadata. Check the array length:

export function MyMultiInput({ data, cardMetadata }: MultiInputVisualProps) {
  console.log('Metadata array:', cardMetadata);
  console.log('Data array length:', data?.length);
 
  // cardMetadata[0] = first slot's metadata
  // cardMetadata[1] = second slot's metadata
  // etc.
}

See the Multi-Input Guide for detailed troubleshooting.


Getting Help

If you're still stuck:

  1. Check browser console: Look for JavaScript errors
  2. Check network tab: Verify plugin bundle is loading
  3. Simplify: Start with a minimal component and add complexity
  4. Contact support: support@semaphor.cloud