Equation
Renders a LaTeX mathematical expression via KaTeX, with display (block) and inline modes, a token-styled container, and a raw-expression fallback for no-JS environments.
Preview
e^{i\pi} + 1 = 0
Inline math like
a^2 + b^2 = c^2
flows with the text.
<div class="flex flex-col items-center gap-4 p-6">
<x-ui.equation expression="e^{i\pi} + 1 = 0" />
<p class="text-sm text-muted-foreground">
{{ __('Inline math like') }} <x-ui.equation :inline="true" expression="a^2 + b^2 = c^2" /> {{ __('flows with the text.') }}
</p>
</div>
Installation
php artisan ui:add equation
Note
This component ships an Alpine behavior module at
resources/js/ui/equation.js. Import it once from your bundle so it registers on alpine:init:
import './equation.js';
Registry contract
php artisan ui:add equation
writes only the files below. The CLI validates each file hash before writing and asks before it replaces a local change, unless you pass --force.
-
resources/views/components/ui/equation.blade.php -
resources/js/ui/equation.js
- Registry dependencies
- None — installs on its own.
- Packages
-
composer: jml/brok:^0.2npm: katexnpm: alpinejs
Use with AI
A brief for your coding agent: install command, usage, props, guidance and the rules. Copy it, or open a prompt about this component in an assistant.
# Brok UI: Equation (`equation`)
Renders a LaTeX mathematical expression via KaTeX, with display (block) and inline modes, a token-styled container, and a raw-expression fallback for no-JS environments.
Brok UI is a Laravel Blade component registry. Installed components are plain Blade files the app owns.
## Install
```bash
php artisan ui:add equation
```
## Usage
```blade
<div class="flex flex-col items-center gap-4 p-6">
<x-ui.equation expression="e^{i\pi} + 1 = 0" />
<p class="text-sm text-muted-foreground">
{{ __('Inline math like') }} <x-ui.equation :inline="true" expression="a^2 + b^2 = c^2" /> {{ __('flows with the text.') }}
</p>
</div>
```
## Props
- `expression` (string, default `E = mc^2`) — LaTeX expression to render.
- `inline` (bool, default `false`) — Renders inline and baseline-aligned instead of as a centered display block.
## Use when
- Use to summarize, sequence, or present data so users can scan it quickly.
- Rendering a LaTeX mathematical expression as typeset math, inline or as a centered block.
## Avoid when
- Do not add display-only ornament when the user needs actionable structure or exact comparison instead.
- The content is plain text with no mathematical notation; render it as normal text instead. Citing a source rather than typesetting math; use citation instead.
## Anti-patterns
- Adding display ornament without informational value
## Rules
- Use the `<brok:equation>` tag (or `<x-ui.equation>`) in Blade; do not rewrite the component.
- Prefer the documented props and variants over utility-class overrides; when a utility must win, use the `!` important modifier.
- Use semantic design tokens (`bg-primary`, `text-muted-foreground`), never raw colour utilities.
- Keep the `data-slot` attributes; they are the styling and test hooks.
## Links
- Docs: https://brokui.dev/docs/components/equation
- Registry JSON (files, props, contract): https://brokui.dev/r/open/equation.json
Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.
API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| expression | string | E = mc^2 | LaTeX expression to render. |
| inline | bool | false | Renders inline and baseline-aligned instead of as a centered display block. |
Slots
default—
Data slots
Stable hooks for CSS overrides and browser tests.
Behavior
- Renders the raw expression as text first for the no-JS/SSR fallback, then Alpine's init() replaces it with KaTeX-rendered HTML.
- inline switches between an inline-flex baseline-aligned span and a centered block with vertical margin.
- Installs a JavaScript behavior module when the registry item includes resources/js/ui files.
- Declares registry capability flags: a11y, interactive, responsive, rtl, darkMode, localized.
Guidance
Present data for rapid scanning.
Use when
- Use to summarize, sequence, or present data so users can scan it quickly.
- Rendering a LaTeX mathematical expression as typeset math, inline or as a centered block.
Avoid when
- Do not add display-only ornament when the user needs actionable structure or exact comparison instead.
- The content is plain text with no mathematical notation; render it as normal text instead. Citing a source rather than typesetting math; use citation instead.
Use instead
- Table for exact comparison
- Plain text for a single value
Anti-patterns
- Adding display ornament without informational value
- Anatomy
- Theming hooks
Accessibility
- Keyboard
- managed
- Focus
none
- The root carries role=math and an aria-label combining 'Mathematical equation' with the raw expression, so assistive tech gets a readable description even before KaTeX renders.
- Semantic HTML and a stable
data-slotattribute for styling and scripting hooks. - Focus-visible rings use the
ringtoken, so keyboard focus is always visible. - Disabled and invalid states are conveyed to assistive tech, not by color alone.
- Targets WCAG 2.2 AA; verify contrast in light, dark, admin and customer surfaces in the preview.
- Labels go through
__()and layout uses logical properties (ms-*,text-start), so it mirrors underdir="rtl"— flip the preview to RTL to confirm. - Dark mode uses the same semantic tokens under the
darkclass; high contrast follows forced-color system tokens.
Livewire
Add wire:ignore to the component root because its behavior owns rendered DOM.
<div wire:ignore>
<div class="flex flex-col items-center gap-4 p-6">
<x-ui.equation expression="e^{i\pi} + 1 = 0" />
<p class="text-sm text-muted-foreground">
{{ __('Inline math like') }} <x-ui.equation :inline="true" expression="a^2 + b^2 = c^2" /> {{ __('flows with the text.') }}
</p>
</div>
</div>
Source
The exact, editable files ui:add writes
into your app. Previews render this same code; there are no preview-only components.
@props([
'expression' => 'E = mc^2',
'inline' => false,
])
{{--
Equation: renders a LaTeX mathematical expression via KaTeX.
The raw expression is embedded in `data-equation` on the root element and
shown as initial text content inside the render target (no-JS / SSR fallback).
Alpine's `uiEquation` init() reads both attributes and replaces the text with
the KaTeX-rendered HTML output.
Modes:
- Block (default, inline=false): centered display equation with vertical
margin; displayMode:true in KaTeX.
- Inline (inline=true): inline-flex, baseline-aligned; displayMode:false.
KaTeX CSS is imported by equation.js so the build bundles it automatically.
KaTeX's internal stylesheet is third-party and exempt from the registry's
semantic-token rules; the token classes here govern only our wrapper chrome.
--}}
@php
$wrapperClass = $inline
? 'inline-flex items-baseline align-baseline'
: 'my-3 flex justify-center';
@endphp
<span
data-slot="equation"
data-equation="{{ $expression }}"
data-inline="{{ $inline ? 'true' : 'false' }}"
x-data="uiEquation()"
role="math"
{{ $attributes->merge(['class' => $wrapperClass]) }}
aria-label="{{ __('Mathematical equation') }}: {{ $expression }}"
>
{{--
Token-styled container that wraps the KaTeX output.
bg-card + border-border give a subtle frame in both block and inline modes.
The padding and rounding differ between inline and block for readability.
--}}
<span
x-ref="render"
class="{{ $inline ? 'rounded border border-border bg-card px-2 py-0.5 text-sm' : 'rounded-md border border-border bg-card px-4 py-3 text-base' }}"
>{{-- Initial text fallback (shown before JS runs / for no-JS) --}}<code class="font-mono text-sm text-foreground">{{ $expression }}</code></span>
</span>
/**
* Equation behavior (uiEquation).
*
* Renders a LaTeX mathematical expression into a KaTeX output span. The raw
* expression is stored in a data attribute on the root element so it is
* available immediately (for no-JS and for the JS init), and JS replaces it
* with the rendered KaTeX HTML.
*
* Display modes:
* inline=false (default) — block-level display equation (displayMode: true),
* centered with vertical margin.
* inline=true — inline-flex, baseline-aligned, no display mode.
*
* Graceful fallback: if KaTeX throws (malformed expression), the raw LaTeX
* expression is shown in a <code> element rather than leaving a blank space.
*
* Note on KaTeX CSS: `katex/dist/katex.min.css` is imported here so the build
* bundles it automatically. KaTeX's internal styles may include colour literals
* inside *KaTeX's own published CSS* — that is third-party CSS, not our source,
* and is exempt from the registry's raw-colour guard which scans source files.
*
* Teardown: no global listeners are added, so destroy() is a no-op.
*
* Self-registers on `alpine:init` so import order does not matter — import this
* file once from your bundle (e.g. resources/js/ui/index.js).
*/
import katex from 'katex';
import 'katex/dist/katex.min.css';
document.addEventListener('alpine:init', () => {
window.Alpine.data('uiEquation', () => ({
init() {
const el = this.$el;
const expr = el.dataset.equation ?? '';
const isInline = el.dataset.inline === 'true';
const target = this.$refs.render;
if (!target) {
return;
}
try {
const html = katex.renderToString(expr, {
throwOnError: true,
displayMode: !isInline,
output: 'html',
trust: false,
strict: 'warn',
});
target.innerHTML = html;
} catch (_err) {
// Fallback: show the raw expression in a code element.
const code = document.createElement('code');
code.textContent = expr;
target.innerHTML = '';
target.appendChild(code);
}
},
destroy() {},
}));
});
Ownership & lifecycle
Owner, release state, review evidence and adoption for this item.
- Owner
- Platform UI (@JoshJML)
- Current version
-
1.0.4 - Status
- Stable
- License
-
open - Accessibility reviewed
- No review date recorded
- Last breaking change
- No date recorded
- Deprecation
- Not deprecated
- Contract
-
v6 - Foundation
-
≥ 1.0.0