Previously docusaurus.config.ts had `onBrokenLinks: 'warn'`, so broken
internal links produced advisory warnings during build but didn't gate
merges. Tightening to `throw` surfaces every broken internal route at
build time. Three classes of issue fell out:
1. Stale `/docs/...` and `/docs/6.0.0/...` references in the 6.0.0
versioned snapshot. The user-facing docs section was renamed
`docs` → `user-docs` (routeBasePath) at some point after 6.0.0 was
cut, but the snapshot's links still pointed at the old prefix. The
live site redirects /docs/* → /user-docs/* at runtime, but
Docusaurus's onBrokenLinks checker doesn't honor redirects.
Bulk-rewrote /docs/* → /user-docs/* across the snapshot (and one
/docs/api → /developer-docs/api).
2. Bare-relative MDX links like `[Label](./mcp)` (no .md/.mdx
extension). Docusaurus renders an absolute href in SSR HTML, so
static crawlers see correct links — BUT React Router's `<Link>`
component on the client side resolves the bare path relative to
the current URL on click, so when the page URL has a trailing
slash (e.g. /extensions/overview/), `./mcp` becomes
/extensions/overview/mcp (404). This is exactly the broken-flow a
user reported on /developer-docs/extensions/overview/. Added the
`.md`/`.mdx` extension to all 44 such links across 17 files; this
makes Docusaurus resolve them to the canonical doc URL at the
<Link> level, so SPA navigation works regardless of trailing slash.
3. Miscellaneous content fixes:
- 4 `/configuration/feature-flags` references in 6.0.0 snapshot
pointed at a page that doesn't exist in that version (the
dedicated feature-flags page was added later). Repointed to the
`#feature-flags` anchor inside `configuring-superset.mdx`.
- 3 references to `superset-core/src/superset_core/rest_api/decorators.py`
in extensions docs were rendered as relative URLs, resolving to
/developer-docs/extensions/superset-core/... (404). Converted to
absolute GitHub URLs.
- 1 `/storybook/?path=...` link in extensions/components/index.mdx
pointed at a non-existent route. Repointed to the existing
`/developer-docs/testing/storybook` page that explains how to
run Storybook locally.
- 4 unclosed-paren markdown links in 6.0.0 installation-methods.mdx
(pre-existing source bugs).
Build now passes with `onBrokenLinks: 'throw'`. Note that
`onBrokenAnchors` is still `'warn'` (default); a separate effort
should tighten that and fix the surviving anchor warnings (currently
~60 instances of `/community#superset-community-calendar`).
6.9 KiB
title, sidebar_position
| title | sidebar_position |
|---|---|
| Component Style Guidelines and Best Practices | 2 |
Component Style Guidelines and Best Practices
This documentation illustrates how we approach component development in Superset and provides examples to help you in writing new components or updating existing ones by following our community-approved standards.
This guide is intended primarily for reusable components. Whenever possible, all new components should be designed with reusability in mind.
General Guidelines
- We use Ant Design as our component library. Do not build a new component if Ant Design provides one but rather instead extend or customize what the library provides
- Always style your component using Emotion and always prefer the theme variables whenever applicable. See: Emotion Styling Guidelines and Best Practices
- All components should be made to be reusable whenever possible
- All components should follow the structure and best practices as detailed below
Directory and component structure
superset-frontend/src/components
{ComponentName}/
index.tsx
{ComponentName}.test.tsx
{ComponentName}.stories.tsx
Components root directory: Components that are meant to be re-used across different parts of the application should go in the superset-frontend/src/components directory. Components that are meant to be specific for a single part of the application should be located in the nearest directory where the component is used, for example, superset-frontend/src/Explore/components
Exporting the component: All components within the superset-frontend/src/components directory should be exported from superset-frontend/src/components/index.ts to facilitate their imports by other components
Component directory name: Use PascalCase for the component directory name
Storybook: Components should come with a storybook file whenever applicable, with the following naming convention \{ComponentName\}.stories.tsx. More details about Storybook below
Unit and end-to-end tests: All components should come with unit tests using Jest and React Testing Library. The file name should follow this naming convention \{ComponentName\}.test.tsx. Read the Testing Guidelines and Best Practices for more details
Reference naming: Use PascalCase for React components and camelCase for component instances
BAD:
import mainNav from './MainNav';
GOOD:
import MainNav from './MainNav';
BAD:
const NavItem = <MainNav />;
GOOD:
const navItem = <MainNav />;
Component naming: Use the file name as the component name
BAD:
import MainNav from './MainNav/index';
GOOD:
import MainNav from './MainNav';
Props naming: Do not use DOM related props for different purposes
BAD:
<MainNav style="big" />
GOOD:
<MainNav variant="big" />
Importing dependencies: Only import what you need
BAD:
import * as React from "react";
GOOD:
import React, { useState } from "react";
Default VS named exports: As recommended by TypeScript, "If a module's primary purpose is to house one specific export, then you should consider exporting it as a default export. This makes both importing and actually using the import a little easier". If you're exporting multiple objects, use named exports instead.
As a default export
import MainNav from './MainNav';
As a named export
import { MainNav, SecondaryNav } from './Navbars';
ARIA roles: Always make sure you are writing accessible components by using the official ARIA roles
Use TypeScript
All components should be written in TypeScript and their extensions should be .ts or .tsx
type vs interface
Validate all props with the correct types. This replaces the need for a run-time validation as provided by the prop-types library.
type HeadingProps = {
param: string;
}
export default function Heading({ children }: HeadingProps) {
return <h2>{children}</h2>
}
Use type for your component props and state. Use interface when you want to enable declaration merging.
Define default values for non-required props
In order to improve the readability of your code and reduce assumptions, always add default values for non required props, when applicable, for example:
const applyDiscount = (price: number, discount = 0.05) => price * (1 - discount);
Functional components and Hooks
We prefer functional components and the usage of hooks over class components.
useState
Always explicitly declare the type unless the type can easily be assumed by the declaration.
const [customer, setCustomer] = useState<ICustomer | null>(null);
useReducer
Always prefer useReducer over useState when your state has complex logics.
useMemo and useCallback
Always memoize when your components take functions or complex objects as props to avoid unnecessary rerenders.
Custom hooks
All custom hooks should be located in the directory /src/hooks. Before creating a new custom hook, make sure that is not available in the existing custom hooks.
Storybook
Each component should come with its dedicated storybook file.
One component per story: Each storybook file should only contain one component unless substantially different variants are required
Component variants: If the component behavior is substantially different when certain props are used, it is best to separate the story into different types. See the superset-frontend/src/components/Select/Select.stories.tsx as an example.
Isolated state: The storybook should show how the component works in an isolated state and with as few dependencies as possible
Use args: It should be possible to test the component with every variant of the available props. We recommend using args