Composition Governance Rules

Experimental

Govern how components are arranged inside a container — not just whether a single node is valid, but whether a region holds the right mix of children.

Overview

Composition rules run over the same usage facts as every other governance rule, but they reason about a region: a container node and the components nested under it. A region is matched by its canonical container component — for example a ButtonGroup — and is local to one element tree, so the same pattern in two separate groups is two separate regions.

Composition is decided statically. A child counts only when its prop resolves to a literal value — a dynamic variant={kind} is unknown, never treated as a match and never treated as absent. Dynamic arrangements are out of scope for these rules.

Rules

  • composition/cardinality (FUI5003): Flags more than the allowed number of a selected component in one region. Example: two primary Buttons in a single ButtonGroup when max is 1.
  • composition/co-occurrence (FUI5004): Flags a selected component that is missing a companion the policy requires in the same region. Example: a primary Button in a ButtonGroup with no secondary Button.

Authoring

Patterns are authored once and read by every surface. Define them as governance policy, where each pattern names a region, a child selector, and a constraint:

fragments.config.ts
export default {
  govern: {
    rules: {
      'composition/cardinality': {
        enabled: true,
        severity: 'warn',
        options: {
          patterns: [
            {
              region: { component: 'ButtonGroup' },
              select: { component: 'Button', prop: 'variant', value: 'primary' },
              constraint: { kind: 'cardinality', max: 1 },
            },
          ],
        },
      },
    },
  },
};

Components can also carry their own composition contract. The authoring block below lowers to the same patterns the rule reads, so the constraint travels with the component:

ButtonGroup.fragment.tsx
contract: {
  composition: [
    {
      inRegion: 'ButtonGroup',
      rule: { atMost: 1, of: { component: 'Button', prop: 'variant', value: 'primary' } },
    },
    {
      inRegion: 'ButtonGroup',
      rule: {
        when: { component: 'Button', prop: 'variant', value: 'primary' },
        require: { prop: 'variant', value: 'secondary' },
      },
    },
  ],
};

Surfaces

Because composition findings flow through the shared engine, they ride every rung of the governance ladder without extra wiring:

  • Editor. The Fragments LSP shows the violation as a warning squiggle as you type, with its FUI code linking to the explain page.
  • CI. The same findings annotate the governance check on a pull request at merge time.
  • Cloud. Fragments Cloud accepts the composition rule IDs and lists them in the Findings filters under the Composition category — no per-rule registration required.