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