--- url: https://ooui-react.pages.dev/en/guide/usage.md --- > For AI agents: the complete documentation index is available at https://ooui-react.pages.dev/en/llms.txt, the full documentation bundle is available at https://ooui-react.pages.dev/en/llms-full.txt. # Usage ## Installation ```sh [npm] npm install ooui-react ``` ```sh [yarn] yarn add ooui-react ``` ```sh [pnpm] pnpm add ooui-react ``` ```sh [bun] bun add ooui-react ``` ```sh [deno] deno add npm:ooui-react ``` React ≥ 18 is required. ## Runtime environment - **Browser-oriented; server-side rendering (SSR) is not supported**: floating components (`Popup`, dropdown menus, toolbar popup panels) resolve their portal container and call `createPortal` during render, which throws immediately on the server where `document` doesn't exist. With isomorphic frameworks such as Next.js, keep these components out of the server render tree, or render them only after mounting on the client. - **Both ESM and CJS builds are shipped, and they are separate module instances**: when a Node process loads the package through both `import` and `require`, the message registry and the `OOUIProvider` context are not shared; bundling for browsers is unaffected. Outside MediaWiki sites, you have to load OOUI's theme CSS and the Codex design tokens yourself — as of oojs-ui 0.54, the token stylesheet must be loaded alongside it. Pick one theme stylesheet: wikimediaui is the current default, while apex is the legacy theme (some states look different between the two; the class names emitted by this library are valid under both): ```js import "@wikimedia/codex-design-tokens/dist/theme-wikimedia-ui.css"; // Pick one of the themes: import "oojs-ui/dist/oojs-ui-wikimediaui.css"; import "oojs-ui/dist/oojs-ui-apex.css"; ``` The OOUI theme is sized against MediaWiki's body font size of 14px; keep your host page consistent with it. :::tip The navbar of this site offers a "Preview theme" switcher to view all live demos under either wikimediaui or apex. The library itself ships no styles — whatever theme you switch to is exactly how the demos will look under it. ::: ## Using it on a MediaWiki site This library was built first and foremost for user gadgets on MediaWiki sites. If bundle size matters to you, use the [Preact compatibility layer](#preact-compatibility) instead of full React. For working examples, see [my Moegirlpedia gadgets repository](https://github.com/BearBin1215/MoegirlPedia): - [`src/gadgets/AdvancedSearch`](https://github.com/BearBin1215/MoegirlPedia/tree/master/src/gadgets/AdvancedSearch) - [`src/gadgets/DynamicRecentChanges`](https://github.com/BearBin1215/MoegirlPedia/tree/master/src/gadgets/DynamicRecentChanges) - [`src/gadgets/FileInspector`](https://github.com/BearBin1215/MoegirlPedia/tree/master/src/gadgets/FileInspector) ### Declaring dependencies On a MediaWiki site the OOUI styles are served by its built-in `oojs-ui` resource modules. Load them at runtime with `mw.loader.using` or in your gadget's ResourceLoader definition: ```ts mw.loader.using([ "oojs-ui", // base OOUI styles "oojs-ui.styles.icons-media", // CSS of the matching OOUI icon pack ]); ``` The icon pack names are listed by group on the [Icon component page](https://ooui-react.pages.dev/en/components/icon/index.md#all-icons). ### Mounting We recommend rendering into a `div` or a `DocumentFragment`, then inserting it before or after an anchor: **index.tsx** ```tsx import React from "react"; import { createRoot } from "react-dom/client"; import App from "./App"; $(async () => { await mw.loader.using(["oojs-ui"]); const fragment = document.createDocumentFragment(); createRoot(fragment).render(); // e.g. insert before the Recent Changes list document.querySelector(".mw-changeslist")!.before(fragment); }); ``` **App.tsx** ```tsx import { Button } from "ooui-react"; function App() { return ; } export default App; ``` ## Preact compatibility This library runs on the Preact compatibility layer (`preact/compat`); see the [official guide](https://preactjs.com/guide/getting-started/#aliasing-react-to-preact) for aliasing. - Requires Preact ≥ 10.18; both 10.x and 11.x are supported. - `react-dom/client` must be aliased to `preact/compat/client`; without it the imperative APIs (`confirm` / `alert` / `prompt`) fail because `createRoot` is not available. ## Working with AI This docs site is built with `llms` support: besides the copy-Markdown and open-in-ChatGPT/Claude entries under each page title, two plain-text files for LLMs are published alongside the site on every build: - [llms.txt](https://ooui-react.pages.dev/en/llms.txt): an index file with descriptions and links for every page on the site ``` https://ooui-react.pages.dev/en/llms.txt ``` - [llms-full.txt](https://ooui-react.pages.dev/en/llms-full.txt): the entire English site content merged into one file ``` https://ooui-react.pages.dev/en/llms-full.txt ``` The Chinese site publishes the same files at the root: `/llms.txt` and `/llms-full.txt`. When citing a single page, appending `.md` to its URL also gives you the plain-Markdown version of that page. Copy whichever link fits your use case and hand it to your agent. --- url: https://ooui-react.pages.dev/en/guide/ooui.md --- > For AI agents: the complete documentation index is available at https://ooui-react.pages.dev/en/llms.txt, the full documentation bundle is available at https://ooui-react.pages.dev/en/llms-full.txt. # Coming from OOUI ooui-react reimplements OOUI's interaction semantics and DOM structure while reusing the original theme CSS, but its API is idiomatic React. Whether you know OOUI and want to lean on that experience in a new script, or are rewriting an old, complex OOUI script, this page maps the two APIs: start with the concept mapping, locate components by their original class names, then check the dropped capabilities and behavioral differences. ## Concept mapping The original imperative API is uniformly expressed as declarative props in this library; see [Controlled and uncontrolled](https://ooui-react.pages.dev/en/guide/controlled.md) for the rules: | Original | ooui-react | | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `setValue` / `setDisabled` / `setPage` setters | Controlled props such as `value` / `defaultValue` / `onChange` | | `WindowManager.openWindow` / `closeWindow` | The Dialog family takes a required `open` prop only; close intent is reported via `onEscape` and other callbacks, see [Dialogs must be controlled](https://ooui-react.pages.dev/en/guide/controlled.md#dialogs-must-be-controlled) | | `updateState` / `choose` / `toggle` events | Callback props such as `onChange` / `onChoose` / `onOpenChange` | | `OO.ui.msg` global and `OO.ui.deferMsg` | The `messages` config and `useMessage` of `OOUIProvider`, see [Global configuration](https://ooui-react.pages.dev/en/guide/configuration.md) | | `OO.ui.isMobile()` (stub that always returns `false`) | The `isMobile` config of `OOUIProvider` | | `OO.ui.HtmlSnippet` (raw-output wrapper) | Write `ReactNode` directly; strings are escaped by default, and there is no dedicated wrapper for raw HTML — use `dangerouslySetInnerHTML` yourself and own the risk | | `OO.ui.Theme` runtime object (`getElementClasses` hooks) | None. Class names are emitted by components following wikimediaui semantics; theme styles come from site CSS. Under third-party themes such as apex a few state classes appear that the original would not output (e.g. progressive coloring on selected options) — a known deviation | | `ToolFactory` / `ToolGroupToolFactory` registration | Declarative data: pass a `tools` array to the toolbar and nest tool groups as React elements, see [Toolbar](https://ooui-react.pages.dev/en/components/toolbar/index.md) | ## Locating components and classes Component names = original class names minus the `Widget` suffix (`ButtonWidget` → `Button`, `TextInputWidget` → `TextInput`). A few names do not work after the suffix is removed and keep their original form: `SearchWidget`, `HiddenInputWidget`, `SelectFileInputWidget`, `ButtonMenuSelectWidget`. Some original classes do not map to standalone components; here is how they are handled: | Original class | How it is handled | | --------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `OO.ui.WindowManager` | Each Dialog component owns its open/close state (controlled `open`); content isolation and stacking are built in. Imperative `confirm` / `alert` / `prompt` need no manager | | `OO.ui.ActionWidget` / `ActionSet` / `OO.ui.Error` | Inlined into `ProcessDialog`: the action array, mode filtering and the error panel, see [Process dialog](https://ooui-react.pages.dev/en/components/process-dialog/index.md) | | `OO.ui.Process` | The `onAction` async callback; rewrite `.next()` chains as one async function | | `OO.ui.OutlineControlsWidget` | Inlined into `BookletLayout`'s outline panel, see [Booklet layout](https://ooui-react.pages.dev/en/components/booklet-layout/index.md) | | `OO.ui.SelectWidget` | [`Select`](https://ooui-react.pages.dev/en/components/select/index.md) | | `OO.ui.PopupTagMultiselectWidget` (deprecated upstream) | Not provided; use [MenuTagMultiselect](https://ooui-react.pages.dev/en/components/menu-tag-multiselect/index.md) | | `OO.ui` host-environment utilities (`bind` / `infuse` / `getUserLanguages` / `generateElementId` / `debounce` / `Keys` / `MouseButtons` etc.) | Not mapped: React's own capabilities, `useId` and es-toolkit cover these scenarios | ## Dropped capabilities The following original capabilities are intentionally not implemented, indexed by original API name: | Original capability | What to do instead | | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `href` on `TabOption` | Not supported (the original only used it from PHP); compose link tabs yourself, see [Tab select](https://ooui-react.pages.dev/en/components/tab-select/index.md) | | `allowLinebreaks` / `enter` on `MultilineTextInputWidget` | Line breaks are always allowed; strip them yourself when you need to forbid them, see [Multiline text input](https://ooui-react.pages.dev/en/components/multiline-text-input/index.md) | | `config.input` / `inputWidget` on `TagMultiselectWidget` | The input is built in and cannot be replaced | | `config.input` on `LabelWidget` | Use `htmlFor` for fields with an id, otherwise let FieldLayout wire the association, see [Label](https://ooui-react.pages.dev/en/components/label/index.md) | | `ActionSet.static.specialFlags` subclass override | Special actions are fixed to `safe` / `primary`; declare them via `flags` | | `align='inline'` downgrade check on `FieldLayout` | No automatic downgrade; make sure the field root element is inline before passing `inline` | | `flags` on plain-label options (Tab / Radio / CheckboxMultioption) | `flags` is only available on option forms with icon slots, see [Selections and options](https://ooui-react.pages.dev/en/guide/options.md) | | Automatic URL sanitizing (`OO.ui.isSafeUrl`) | Components never rewrite `href` / `action`; sanitize untrusted URLs yourself with the exported `sanitizeUrl` (the responsibility is on the caller and the backend), see [Button](https://ooui-react.pages.dev/en/components/button/index.md) | ## Behavioral differences at a glance These behaviors differ from the original in ways that will break or surprise you if unaddressed, indexed by component. Details live on each component page: | Component | Difference | Details | | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- | | `Message` | The close button only calls `onClose` and does not hide itself — if you ignore the callback the message cannot be dismissed | [Message](https://ooui-react.pages.dev/en/components/message/index.md) | | Bare `Dialog` | No built-in title slot; render the title yourself and pass `aria-labelledby`, otherwise you get an unnamed dialog | [Dialog](https://ooui-react.pages.dev/en/components/dialog/index.md) | | Dialog family | Always controlled: a required `open` prop, no `defaultOpen` | [Controlled and uncontrolled](https://ooui-react.pages.dev/en/guide/controlled.md#dialogs-must-be-controlled) | | `confirm` / `alert` / `prompt` | The original silently drops the second call while a window is open; this library stacks them, each independently interactive | [Imperative dialogs](https://ooui-react.pages.dev/en/components/imperative-dialogs/index.md) | | `prompt` | `textInput.value` is initial-only; it cannot be changed externally while the dialog is alive | [Imperative dialogs](https://ooui-react.pages.dev/en/components/imperative-dialogs/index.md) | | `Toolbar` tools | Visible text and tooltip split from one `title` key into `label` + `title` (pass the old `narrowConfig.title` value as `label`) | [Toolbar](https://ooui-react.pages.dev/en/components/toolbar/index.md) | | `Toolbar` | Do not put popup tools inside List / Menu groups: the popup anchor becomes invalid once the panel collapses, and the popup ends up misplaced at the viewport's top-left corner | [Toolbar](https://ooui-react.pages.dev/en/components/toolbar/index.md) | | `TagMultiselect` | Tag identity is a scalar `value`; carry objects in the `data` field and look them up by value | [Tag multiselect](https://ooui-react.pages.dev/en/components/tag-multiselect/index.md) | | `Dropdown` / `ButtonMenuSelectWidget` | Space selects the highlighted option while open (the original ignored Space and only closed the menu via key-press click emulation) | [Dropdown](https://ooui-react.pages.dev/en/components/dropdown/index.md) | | `Popup` | Re-evaluates the flip direction when scrolling changes clipping (the original freezes it until reopened); the popup may jump while scrolling | [Popup](https://ooui-react.pages.dev/en/components/popup/index.md) | ## Imperative dialogs `confirm` / `alert` / `prompt` are standalone functions you can `await` from any event handler; the dialogs inherit the enclosing `OOUIProvider` configuration (messages, `isMobile`, `dir` and your own providers). Unlike the original's shared singleton manager, repeated calls stack. See [Imperative dialogs](https://ooui-react.pages.dev/en/components/imperative-dialogs/index.md) for the runtime semantics and [Global configuration](https://ooui-react.pages.dev/en/guide/configuration.md#imperative-dialogs) for config inheritance. ## Localization `en` is the built-in default baseline; 222 more language packs (`ooui-react/locales/`) are available as optional imports. On a MediaWiki site you can wire `mw.msg` into `messages` to follow the site language. See [Messages and i18n](https://ooui-react.pages.dev/en/guide/configuration.md#messages-and-i18n) for the language list and setup. ## Full list of deviations This page lists only the differences that affect usage. The complete list (including implementation-level trade-offs and rationale) is in the repository's [`dev-docs/DEVIATIONS.md`](https://github.com/BearBin1215/ooui-react/blob/main/dev-docs/DEVIATIONS.md). --- url: https://ooui-react.pages.dev/en/guide/basics.md --- > For AI agents: the complete documentation index is available at https://ooui-react.pages.dev/en/llms.txt, the full documentation bundle is available at https://ooui-react.pages.dev/en/llms-full.txt. # Common props This page is the shared premise for every component page; it covers the prop rules and where props are written that **all components have in common**. Component-specific props are documented on each component's own page. ## Prop pass-through Components forward any prop this library does not declare straight onto the rendered root element, so `className`, `id`, `style`, `data-*`, `aria-*`, `onClick` and the like can be written directly: ```tsx preview import { Button } from "ooui-react"; function App() { return (
); } export default App; ``` - If a component always writes a given prop onto the root element itself, pass-through won't take effect — for example, `aria-disabled` on most components is derived from the `disabled` prop and can't be set by hand. - The native `defaultValue` / `defaultChecked` are not written to the DOM by pass-through. ## Refs and inner elements `ref` points at the root element. To reach an inner element or pass props to it, use the channel the component exposes: | Channel | Points at / does | Provided by | | ------------------------------ | -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `inputRef` | The inner `` / `