Skip to content
3 changes: 2 additions & 1 deletion docs/contributing/transpile-diff.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: Comparing Transpiled Output
category: Contributor Guides
category: Contributing
order: 8
---

# Comparing Transpiled Output
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/accessing-the-dom.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Accessing the DOM
category: Guides
order: 3
order: 4
relevantForAI: true
---

Expand Down
108 changes: 108 additions & 0 deletions docs/guides/component-versioning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
title: Component versioning
category: Guides
order: 2
---

## Why components are versioned

When InstUI needs to make a breaking change to a component (renamed props, changed behaviour, etc.), the old version is **kept alongside the new one** instead of being replaced. Upgrading the library no longer forces you to immediately rewrite every component usage — you can migrate to new versions on your own schedule.

New component versions appear with InstUI **minor** version bumps (e.g. `11.7` → `11.8`). Patch releases never include breaking changes.

## Import paths

Every InstUI component package supports three import styles:

### Default — `@instructure/ui-<name>`

Always points to the **oldest** still-supported component version. Upgrading the library without changing your imports will keep your code working without surprises.

```js
---
type: code
---
import { Alert } from '@instructure/ui-alerts'
```

### Pinned — `@instructure/ui-<name>/v11_X`

Locks the import to a specific InstUI minor version of the component. When you are ready to adopt a breaking change, update the path to the next pinned version.

```js
---
type: code
---
import { Alert } from '@instructure/ui-alerts/v11_7'
```

### Latest — `@instructure/ui-<name>/latest`

Always points to the newest component version. This may bring breaking changes when you upgrade InstUI itself.

```js
---
type: code
---
import { Alert } from '@instructure/ui-alerts/latest'
```

### Per-package or umbrella package

InstUI also ships an umbrella package, `@instructure/ui`, which re-exports every component from the individual `@instructure/ui-*` packages. Two equivalent import styles work — both resolve to the same component:

```js
---
type: code
---
// per-package import
import { Alert } from '@instructure/ui-alerts/v11_7'

// umbrella package import
import { Alert } from '@instructure/ui/v11_7'
```

The same three path styles (default / `/v11_X` / `/latest`) work on the umbrella package as well. Pick per-package imports when you want better tree-shaking and only pull in what you use, or the umbrella package when you'd rather depend on a single `@instructure/ui` entry in your `package.json`.

## Versions and theming engines

InstUI is in the middle of a transition between two theming systems. Which engine a component uses depends on which version you import:

- **`v11_6` and earlier** — legacy theming. Components are configured through the Canvas theme variables and the `themeOverride` prop, which accepts a function or object that maps to the component's own theme map. See the [Legacy theme overrides](legacy-theme-overrides) guide.

- **`v11_7` and newer** — new theming system. Components consume pre-resolved design tokens, and theming is done through the new token override structure. See the [New theme overrides](new-theme-overrides) guide.

Mixing imports from both groups in the same app is fully supported — the two engines run side-by-side without conflict.

### Supported themes per version

You import themes the same way as before — from `@instructure/ui-themes` — and pass them to `InstUISettingsProvider`:

```js
---
type: code
---
import { canvas } from '@instructure/ui-themes'

<InstUISettingsProvider theme={canvas}>
<App />
</InstUISettingsProvider>
```

The `canvas` (and `canvasHighContrast`) export works for **both `v11_6` and `v11_7+` components in the same app** — internally it carries the data each engine needs. You don't need to switch theme objects when you bump a component import to `/v11_7`.

- **`v11_6` and earlier** — supports the original two themes:

- `canvas` — default theme used by Canvas products
- `canvasHighContrast` — same as `canvas`, with colors WCAG-tuned for high-contrast accessibility

- **`v11_7` and newer** — supports the same two themes (rendered through the new engine, labelled `(legacy)` in the docs UI Theme selector) plus two brand-new ones:

- `canvas` — same import as above, now driven by the new engine (labelled as `(legacy)`)
- `canvasHighContrast` — same import as above, now driven by the new engine (labelled as `(legacy)`)
- `light` — new light theme
- `dark` — new dark theme

This means that when you move a component import from `/v11_6` to `/v11_7`, you can continue using the `canvas` theme to maintain a familiar look and feel, and opt in to `light` or `dark` only when you're ready.

> The `@instructure/ui-themes` package also exports `legacyCanvas` and `legacyCanvasHighContrast`. These are the raw new-engine forms that `canvas` / `canvasHighContrast` wrap internally — most consumers don't need to import them directly.
2 changes: 1 addition & 1 deletion docs/guides/forms.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Forms
category: Guides
order: 4
order: 5
relevantForAI: true
---

Expand Down
2 changes: 1 addition & 1 deletion docs/guides/module-federation.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Module federation
category: Guides
order: 2
order: 3
relevantForAI: true
---

Expand Down
9 changes: 0 additions & 9 deletions docs/theming/legacy-theme-overrides.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,6 @@ relevantForAI: true

## Using theme overrides

```js
---
type: embed
---
<Alert variant="warning" margin="0 0 medium">
The examples on this page use the <strong>legacy theming system</strong> and are designed for <strong>v11.6</strong> components. If you are viewing the v11.7 version, <Link href={window.location.pathname.match(/v\d+_\d+/) ? window.location.pathname.replace(/v\d+_\d+/, 'v11_6') : `/v11_6${window.location.pathname}`}>switch to v11.6</Link> to see the examples working correctly.
</Alert>
```

This document gives an overview on how you can customize Instructure UI components by tweaking their theme variables.
While this gives you a level of flexibility on the look and feel of the components you should be aware of 2 things:

Expand Down
56 changes: 45 additions & 11 deletions docs/theming/new-theme-overrides.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,6 @@ relevantForAI: true

## New Theme Override Patterns

```js
---
type: embed
---
<Alert variant="warning" margin="0 0 medium">
The examples on this page use the <strong>new theming system</strong> and require <strong>v11.7+</strong> components. If you are viewing the v11.6 version, <Link href={window.location.pathname.match(/v\d+_\d+/) ? window.location.pathname.replace(/v\d+_\d+/, 'v11_7') : `/v11_7${window.location.pathname}`}>switch to v11.7</Link> to see the examples working correctly.
</Alert>
```

This guide covers all the override patterns available in the new theming system (v11.7+). The new system uses a layered token architecture: **primitives** (raw values) -> **semantics** (meaning) -> **components** (per-component tokens).

Overrides are applied via the `themeOverride` prop on `InstUISettingsProvider`, which is separate from the `theme` prop. The `theme` prop replaces the active theme entirely; `themeOverride` layers modifications on top.
Expand Down Expand Up @@ -527,9 +518,52 @@ type: example
</InstUISettingsProvider>
```

### 13. Provider-level overrides cannot target a child component selectively
### 13. Independent overrides for child parts of compound components

Most compound components expose each part as a separate component with its own `componentId`. This means you can independently override each part via `components` — both overrides take effect:

```js
---
type: example
---
<InstUISettingsProvider theme={canvas}>
<InstUISettingsProvider
themeOverride={{
components: {
TableColHeader: {
background: 'rebeccapurple',
color: 'gold'
},
TableRowHeader: {
background: 'deeppink',
color: 'white'
}
}
}}
>
<Table caption="Independent overrides: ColHeader purple, RowHeader deeppink">
<Table.Head>
<Table.Row>
<Table.ColHeader id="row-headers">Row headers column - purple</Table.ColHeader>
<Table.ColHeader id="cells">Cells column - purple</Table.ColHeader>
</Table.Row>
</Table.Head>
<Table.Body>
<Table.Row>
<Table.RowHeader>TableRowHeader — deeppink</Table.RowHeader>
<Table.Cell>TableCell — unchanged</Table.Cell>
</Table.Row>
<Table.Row>
<Table.RowHeader>TableRowHeader — deeppink</Table.RowHeader>
<Table.Cell>TableCell — unchanged</Table.Cell>
</Table.Row>
</Table.Body>
</Table>
</InstUISettingsProvider>
</InstUISettingsProvider>
```

Because `Button` uses `BaseButton`'s theme internally, a `components.Button` entry in the provider's `themeOverride` does **not** override `BaseButton`'s tokens for `Button` instances only. Both `BaseButton` and `Button` share the same `BaseButton` theme variables, so a `components.BaseButton` override affects both, regardless of whether a separate `components.Button` entry is also present.
**Exception — `Button` and `BaseButton`:** `Button` uses `BaseButton`'s `componentId` internally, so `components.Button` has no effect. A `components.BaseButton` override affects all `BaseButton` instances including those rendered inside `Button` — there is no way to target only one:

```js
---
Expand Down
Loading
Loading