Skip to main content

Layout and Testing

Understanding how widgets adapt to different screen sizes and ensuring they are accessible and well-tested is crucial for building robust, production-ready widgets. This guide covers responsive design patterns, comprehensive testing strategies, and accessibility best practices.

Layout and Responsive Design

Full spec

The platform's grid math (how layout maps to pixels, auto-layout) is defined in the Manual: Layout Calculation. This page covers how to use it in your widget.

Layout Props

Widgets receive layout information via props:

interface IWidgetProps {
layout?: {
w: number; // Width in grid units
h: number; // Height in grid units
x: number; // X position in grid
y: number; // Y position in grid
};
}

Layout Constraints

Defined in widget-config.json:

{
"layout": {
"minW": 5,
"maxW": 24,
"minH": 5,
"maxH": 12
}
}

React Grid Layout Integration

The Dashboard Composer (Host application) uses a responsive grid system based on viewport breakpoints. The number of grid columns changes based on the current breakpoint.

Grid Configuration:

const rgl = {
cols: {
lg: 36, // Large screens
md: 24, // Medium screens
sm: 12, // Small screens
xs: 6, // Extra small screens
},
};

Viewport Breakpoints:

const VIEWPORT_BREAKPOINTS = {
EXTRA_EXTRA_SMALL: 0,
EXTRA_SMALL: 320,
SMALL: 768,
MEDIUM: 1220,
LARGE: 1920,
};

Breakpoint Examples:

  • Resolution 321px - 767px: Grid has 6 columns (xs)
  • Resolution 768px - 1219px: Grid has 12 columns (sm)
  • Resolution 1220px - 1919px: Grid has 24 columns (md)
  • Resolution 1920px+: Grid has 36 columns (lg)

Dashboard Composer Breakpoint Controls

The Dashboard Composer provides 4 predefined breakpoints for users to switch between during dashboard configuration. When switching to a breakpoint different from the current viewport, the dashboard width is set to a specific value:

  • XS: 390px
  • SM: 1024px
  • MD: 1480px
  • LG: 1921px

This allows users to preview and configure their dashboards for different screen sizes.

Responsive Widget Example

Use container queries so the layout adapts to the widget's own width (as it's resized on the dashboard), not to the browser viewport. Opt a subtree in with @container, then use @[width]: variants:

import React from 'react';

const ResponsiveKpiTracker = () => {
return (
<div className="@container h-full w-full p-3">
<div className="grid grid-cols-1 gap-2 @[400px]:grid-cols-2 @[640px]:grid-cols-3">
<div className="rounded-md bg-card p-2 text-card-foreground">Revenue</div>
<div className="rounded-md bg-card p-2 text-card-foreground">Users</div>
<div className="rounded-md bg-card p-2 text-card-foreground">Conversion</div>
</div>
</div>
);
};

export default ResponsiveKpiTracker;

You can also read the widget's grid size from the layout prop (layout.w / layout.h) when you need JS-side branching rather than CSS.


Testing and Accessibility

Component Testing

Test Scenarios:

  1. Testing new components
  2. Testing edge cases
  3. Fixing broken tests
  4. Refactoring tests

RTL Query Priority:

  1. Accessible: getByRole, getByLabelText, getByPlaceholderText, getByText
  2. Semantic: getByAltText, getByTitle
  3. Test ID: getByTestId (last resort)

Example Test

Widget tests render the component with mocked platform props and assert on states (loading, data, error). The full testing methodology — environment setup, query priorities, mocking httpClient / shared values, and best practices — lives in the Manual, and the widget-testing skill scaffolds specs for you.

Full spec

UI-Kit Testing — setup, scenarios, RTL query priority, and per-test-type best practices.

Accessibility Testing

Reference: A11y Support

Tools:

  • eslint-plugin-jsx-a11y: Linting for accessibility issues
  • jest-axe: Automated accessibility testing
  • storybook-a11y-addon: Accessibility testing in Storybook
  • @react-aria: Accessible React components
  • Browser tools: axe DevTools extension, Lighthouse

Jest-Axe Example

import React from "react";
import { render } from "@testing-library/react";
import { axe, toHaveNoViolations } from "jest-axe";
import KpiTracker from "./widget";

expect.extend(toHaveNoViolations);

describe("KpiTracker Accessibility", () => {
it("should have no accessibility violations", async () => {
const { container } = render(<KpiTracker {...defaultProps} />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});

Accessible Component Example

import React from 'react';

const AccessibleKpiCard: React.FC<{ label: string; value: string }> = ({ label, value }) => {
return (
<div role="region" aria-labelledby="kpi-label" className="rounded-md bg-card p-4">
<div id="kpi-label" className="text-sm text-muted-foreground">
{label}
</div>
<div aria-live="polite" aria-atomic="true" className="text-2xl font-bold text-foreground">
{value}
</div>
</div>
);
};

export default AccessibleKpiCard;

Code Style

Reference: Code Style

Tools:

  • wl-linters: Centralized linting configuration
  • eslint: JavaScript/TypeScript linting
  • stylelint: CSS linting
  • prettier-eslint: Code formatting
  • Husky: Pre-commit hooks

Commands:

# Lint JavaScript/TypeScript
npm run lint

# Lint styles
npm run lint:styles

# Format code
npm run format

# Run all checks
npm run lint && npm run lint:styles && npm run format