Documentation menu

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.

Installation

Ask Claude (MCP)

With the MCP server configured, just ask:

Claude
add the moco math component

shadcn CLI

Terminal
npx shadcn@latest add https://mocoui.site/r/math.json

Manual

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.css

Needs 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;
  }
}