math
Display equation with a plain-English restatement and a 'show the math' derivation disclosure. Children are typically KaTeX/MathML output — katex is an optional peer, not imported here.
mathprosedisclosure
Preview
A = P(1 + r)ⁿ
Compound growth: the final amount is the start times the rate, applied once per period.
After one period: A₁ = P(1 + r). Each subsequent period multiplies by (1 + r) again, so after n periods the factors stack: A = P(1 + r)ⁿ.
Installation
shadcn CLI
Terminal
npx shadcn@latest add https://mocoui.site/r/math.jsonManual
Copy each file from the Source section into its target path:
registry/math/math.tsx → components/moco/math.tsx
registry/math/math.css → components/moco/math.cssNeeds moco items: tokens
Usage
usage.tsx
"use client";
import * as React from "react";
import { MathBlock } from "./math";
/* In real use `children` is KaTeX or MathML output; plain markup works too. */
export default function MathDemo() {
return (
<MathBlock
plain="Compound growth: the final amount is the start times the rate, applied once per period."
derivation={
<>
<p>
After one period: <code>A₁ = P(1 + r)</code>. Each subsequent period
multiplies by <code>(1 + r)</code> again, so after <code>n</code>{" "}
periods the factors stack: <code>A = P(1 + r)ⁿ</code>.
</p>
</>
}
>
<p style={{ textAlign: "center", fontSize: "1.2em" }}>
<em>A = P(1 + r)ⁿ</em>
</p>
</MathBlock>
);
}
Source
components/moco/math.tsx
"use client";
import * as React from "react";
import "./math.css";
/**
* A display equation with a plain-English restatement under it and a
* progressive-disclosure button for the derivation.
*
* `children` is the rendered equation — typically KaTeX or MathML output.
* katex is not imported here; render the math however you like.
*/
export interface MathBlockProps {
children: React.ReactNode;
plain: string;
derivation?: React.ReactNode;
}
export function MathBlock({ children, plain, derivation }: MathBlockProps) {
const [open, setOpen] = React.useState(false);
const id = React.useId();
return (
<div className="moco-math-block">
{derivation ? (
<div className="moco-math-head">
<button
type="button"
className="moco-btn-sm"
aria-expanded={open}
aria-controls={id}
onClick={() => setOpen((v) => !v)}
>
{open ? "Hide the math" : "Show the math"}
</button>
</div>
) : null}
{children}
<p className="moco-math-plain">{plain}</p>
{derivation ? (
<div id={id} className="moco-math-deriv" hidden={!open}>
{derivation}
</div>
) : null}
</div>
);
}
components/moco/math.css
.moco-math-block {
margin: 2.5rem 0;
}
.moco-math-head {
display: flex;
justify-content: flex-end;
}
.moco-math-plain {
font-family: var(--moco-serif);
color: var(--moco-muted);
font-size: 13.5px;
text-align: center;
margin-top: 0.4rem;
}
.moco-math-deriv {
font-family: var(--moco-serif);
border: 1px solid var(--moco-line);
border-radius: 2px;
padding: 1rem 1.15rem;
margin-top: 1rem;
font-size: 13.5px;
color: var(--moco-muted);
background: var(--moco-panel);
}
.moco-btn-sm {
font: inherit;
border: 1px solid var(--moco-line);
border-radius: 2px;
padding: 0.2rem 0.6rem;
font-size: 12px;
color: var(--moco-muted);
background: var(--moco-bg);
cursor: pointer;
transition:
color 150ms var(--moco-ease),
border-color 150ms var(--moco-ease);
}
.moco-btn-sm:hover {
color: var(--moco-accent-dk);
border-color: var(--moco-accent-dk);
}
@media (prefers-reduced-motion: reduce) {
.moco-btn-sm {
transition-duration: 0.001ms;
}
}