Elements

53 / 122 · Structured output

Math

Rendered expressions with the working shown, one step at a time.

derivation
p(x) = 11 + e−xthe logistic

Installation

npx shadcn@latest add "@assistant-ui/elements-math-block"

Usage

import { MathBlock, Frac, Sup } from "@/components/elements/math-block";

<MathBlock label="derivation" steps={steps} visibleSteps={2} />

Props

MathBlock

labelstringOptional eyebrow above the working.
steps*MathStep[]Each step is a node, so you compose expressions from the exported Frac, Sup, and Sub helpers rather than passing a string to parse.
visibleSteps*numberHow much of the derivation has been shown.
classNamestringExtra classes merged onto the root.

Frac

over*React.ReactNodeNumerator.
under*React.ReactNodeDenominator.

Source

math-block.tsx
"use client";

import { cn } from "@/lib/utils";
import { mono, paper } from "./surfaces";

export interface MathStep {
  expression: React.ReactNode;
  note?: string;
}

export function MathBlock({
  label,
  steps,
  visibleSteps,
  className,
}: {
  label?: string;
  steps: readonly MathStep[];
  visibleSteps: number;
  className?: string;
}) {
  return (
    <div
      className={cn(
        paper,
        "flex w-full max-w-sm flex-col gap-2.5 rounded-2xl p-4",
        className,
      )}
    >
      {label && <span className={cn(mono, "text-foreground/30")}>{label}</span>}

      {steps.slice(0, visibleSteps).map((step, i) => (
        <div
          key={i}
          className="fade-in slide-in-from-bottom-1 animate-in fill-mode-both flex flex-col gap-1 duration-300"
        >
          <span className="text-foreground/90 overflow-x-auto py-1 text-center font-serif text-[17px] leading-relaxed italic">
            {step.expression}
          </span>
          {step.note && (
            <span className={cn(mono, "text-foreground/30 text-center")}>
              {step.note}
            </span>
          )}
        </div>
      ))}
    </div>
  );
}

export function Frac({
  over,
  under,
}: {
  over: React.ReactNode;
  under: React.ReactNode;
}) {
  return (
    <span className="inline-flex flex-col items-center align-middle text-[0.85em] leading-tight">
      <span className="px-1">{over}</span>
      <span className="border-foreground/40 w-full border-t px-1">{under}</span>
    </span>
  );
}

export function Sup({ children }: { children: React.ReactNode }) {
  return <sup className="text-[0.65em] not-italic">{children}</sup>;
}

export function Sub({ children }: { children: React.ReactNode }) {
  return <sub className="text-[0.65em] not-italic">{children}</sub>;
}