Skip to content

Latest commit

 

History

History
16168 lines (11539 loc) · 413 KB

File metadata and controls

16168 lines (11539 loc) · 413 KB

MathLive — Mathfield

Introduction

Source: https://mathlive.io/mathfield

<style>{` .svg-settings { position: absolute !important; height: 1px; width: 1px; overflow: hidden; clip: rect(1px 1px 1px 1px); /* IE6, IE7 */ clip: rect(1px, 1px, 1px, 1px); } #features-section { display: flex; gap: 1rem; align-items: start; flex-flow: row; flex-wrap: wrap; justify-content: space-evenly; margin-bottom: 1rem; } #features-section p { color: var(--neutral-500); font-weight: 600; line-height: 1; font-size: 1rem; } #features-section p strong { color: var(--neutral-0); } #features-section > div { padding: 2rem; border: 1px solid var(--border-color); border-radius: 16px; background: var(--content-background); color: var(--text-color); } @media only screen and (max-width: 767px) { #features-section > div { padding: 16px; } } #use-cases-section { display: flex; flex-flow: row; flex-wrap: wrap; gap: 1rem; justify-content: space-evenly; } div.use-case { display: flex; flex-flow: column; flex-wrap: wrap; align-items: center; margin: 0; padding: 1rem; width: calc(50% - 2rem); max-width: 410px; height: fit-content; border: 1px solid var(--border-color); border-radius: 16px; background: var(--content-background); color: var(--text-color); } div.use-case div { display: flex; flex-flow: column; flex-wrap: wrap; align-items: center; text-align: center; } div.use-case .icon { font-size: 6rem; margin-right: 2rem; margin-left: 1rem; min-width: 120px; width: .875em; } div.use-case h3 { font-size: 2rem; line-height: 1; margin-bottom: 2rem; margin-top: 1rem; } div.use-case h3 .hash-link, div.use-case h3:hover .hash-link { display: none; } div.use-case p { font-size: 1rem; color: var(--body-color); font-weight: 600; line-height: 1.1; } div.use-case > div > p { color: var(--neutral-500); } .fill-purple path { fill: url(#purple-gradient); } .fill-orange path { fill: url(#orange-gradient); } .fill-blue path { fill: url(#blue-gradient); } .fill-yellow path { fill: url(#yellow-gradient); } .fill-green path { fill: url(#green-gradient); } .use-case div { margin: 0; } .use-case .icon { display: flex; align-self: center; justify-self: center; margin: auto; } #features-section p.link { width: 100%; border-radius: 8px; padding: 0; margin-bottom: 2em; /* box-shadow: var(--callout-shadow); background: var(--callout-background); border: 1px solid var(--callout-border-color); */ } #features-section p.link a { font-weight: 600; color: var(--primary-color); } h1 { display: none; } h1.zoom { display: flex; flex-flow: column; justify-content: center; text-align: center; font-size: 8rem; letter-spacing: -0.04em; line-height: .8; font-weight: 700; text-fill-color: transparent; -webkit-text-fill-color: transparent; -moz-text-fill-color: transparent; background-clip: text; -webkit-background-clip: text; -moz-background-clip: text; background-image: linear-gradient(0deg, #b95a52, #2c5072); padding-top: 10rem; padding-bottom: 8rem; margin-left: 0; margin-right: 0; margin-left: -2rem; margin-right: -2rem; margin-top: -2rem; animation: zoom-in-zoom-out 1.2s ease 1; } h1 span.first-part { font-size:140px; } h1 span.second-part { margin-top: 12px; margin-bottom: 12px; font-size: 75px; font-weight: 200; letter-spacing: -6px; /* animation-delay: .2s; */ /* animation: zoom-in-zoom-out 1s ease infinite; */ /* animation: 0.2s zoom-in-zoom-out 1s ease infinite;; */ } h1 span.third-part { font-size: 120px; letter-spacing: -8px; /* animation-delay: .4s; */ /* animation: 0.5s zoom-in-zoom-out 1s ease; */ } @keyframes zoom-in-zoom-out { 0% { transform: scale(0, 0); } 50% { transform: scale(1.2, 1.2); } 100% { transform: scale(1, 1); } } h1::selection, h1 span::selection { -webkit-text-fill-color: #000; background: #abd; background-clip:inherit; -webkit-background-clip: inherit; -moz-background-clip: inherit; } div.intro-copy { display: flex; flex-flow: column; align-items: center; padding-top: 2rem; margin-inline: 0; margin-bottom: 1rem; border: 1px solid var(--border-color); border-radius: 16px; background: var(--content-background); color: var(--text-color); } div.intro-copy p { color: var(--text-color); margin: 0; font-size: 3rem; font-weight: 700; line-height: 1; letter-spacing: 0.006em; } div.intro-copy p.p1 { font-size: 4rem; line-height: .8; letter-spacing: -0.03em; } div.intro-copy p.p2 { margin-top: 1rem; font-size: clamp(18px, 6vw, 2rem); line-height: .8; } div.intro-copy p.p3 { font-size: clamp(18px, 4vw, 1rem); color: var(--neutral-500); font-weight: 600; padding-inline: 1em; } div.intro-copy hr { width: 50%; margin: 1rem 0; border: none; border-top: 1px solid var(--border-color); } div.intro-copy div { display: block; width: 100%; padding-inline: 10%; } @media only screen and (max-width: 767px) { div.intro-copy div { padding-inline: 8px; } } div.intro-copy kbd { font-family: var(--monospace-font); background: transparent; color: var(--primary-color); font-size: clamp(24px, 12vw, 1em); line-height: 1; border: none; box-shadow: none; } h2 { font-size: 2rem; line-height: 1; letter-spacing: -0.03em; } p { margin: 0 0 1em; font-weight: 600; font-size: 1.5rem; line-height: 1.1em; letter-spacing: 0.006em; color: #999; } /* We add #features-section so that this rule does not apply to the global menu button in the header */ #features-section button { appearance: none; border: none; background: var(--primary-color); color: white; padding: 8px 16px 8px 16px; border-radius: 36px; font-weight: 600; margin-bottom: 1rem; } #features-section button:hover { background: var(--primary-color-dark); transition: background-color 0.3s ease-in-out; } [data-theme="dark"] #features-section section button:hover { background: var(--primary-color-light); } #features-section button:active { background: var(--primary-color-dark); scale: 1.05; transition: background-color 0.3s ease-in-out; } [data-theme="dark"] #features-section button:active { background: var(--primary-color-light); } .copy strong { color: #000; } div.figure { display: flex; align-items: center; justify-content: center; overflow: hidden; background: var(--neutral-900); border: 1px solid var(--neutral-700); border-radius: 8px; } @media (prefers-color-scheme: dark) { p { color: #bbb } .copy strong { color: #fff; } } @media only screen and (max-width: 767px) { #main { padding-left:0; padding-right: 0; } .page .page__inner-wrap { padding-left:0; padding-right: 0; } picture.full-width, img.full-width { width: 100%; padding-left:0; padding-right: 0; margin-left:0; margin-right:0; } h1 { font-size: 3rem; } h1 span.first-part { font-size: clamp(2rem, 8vmin, 4.5rem); letter-spacing: -2px; } h1 span.second-part { font-size: clamp(1rem, 3vmin, 3rem); letter-spacing: 0; } h1 span.third-part { font-size: 4rem; letter-spacing: -2px; } p.intro-copy { font-size: 2rem; } #features-section { flex-flow: column; } #use-cases-section { flex-flow: column; gap: 0; } div.use-case { display: flex; flex-flow: column; width: 100%; min-width: 100%; margin-bottom: 1rem; } div.use-case .icon { margin-top: 1rem; margin-bottom: 1rem; } } `}</style> # Mathfield

<math-field>

The Math Editor for the Web


A flexible, powerful, and accessible way to write math on the web.


```live :::style math-field { border: 1px solid var(--neutral-400); background: var(--neutral-200); border-radius: 8px; padding: 8px; } @media (pointer: coarse) { math-field { border-radius: 16px; font-size: 1.25rem; border: 1px solid var(--neutral-100); background: var(--neutral-700); --primary-color: white; color: white; padding: 16px; box-shadow: inset 4px 4px 16px rgb(0 0 0 / 10%), inset 2px 2px 8px rgb(0 0 0 / 60%);
      --smart-fence-color: white;
      --caret-color: var(--blue-400);
      --selection-background-color: var(--blue-300);
      --contains-highlight-background-color: var(--blue-900);
    }
    math-field:focus {
      outline: 4px solid rgb(255 255 255 / 25%);
    }
    math-field::part(virtual-keyboard-toggle), math-field::part(menu-toggle) {
      color: white;
    }
}

:::html

Start typing math below:

x=\frac{-b\pm\sqrt{b^2-4ac}}{2a} ```

Why MathField?

Built on LaTeX

The gold standard, for beautiful math typesetting.

Mathfields support 800 LaTeX commands.

Math Virtual Keyboards

Fully customizable and makes math input easy on desktop and mobile.

Open Source & Extensible

MathField is an open source project available on GitHub. Contributions are welcome.

Individuals and commercial partners are encouraged to support financially the project.

What Can You Do with MathField?

  ### E-Learning Made Engaging

  Enable interactive math quizzes, exercises, and problem-solving tools that check answers in real-time
  
  <ReadMore path="/tutorials/simple-quiz/">
  Read this step-by-step tutorial to build a **simple quiz** <Icon name="chevron-right-bold" />
  </ReadMore>

  <ReadMore path="/mathfield/guides/fill-in-the-blank/" >
  Learn more about authoring **fill-in-the-blank** questions <Icon name="chevron-right-bold" />
  </ReadMore>
</div>
### Scientific Computing & Research

Render complex formulas and let users symbolically manipulate equations.


<ReadMore path="/compute-engine/guides/symbolic-computing/" >
Use mathfields with the <strong>Compute Engine</strong><Icon name="chevron-right-bold" />
</ReadMore>

### Interactive Online Calculators

<p>Build real-time calculators that evaluate math expressions dynamically</p>

<ReadMore path="/compute-engine/guides/numeric-evaluation/" >
Use the <strong>Compute Engine</strong> to evaluate the user's input<Icon name="chevron-right-bold" />
</ReadMore>  

### Beautiful Math Documentation

Embed math seamlessly in **blogs**, **wikis**, and **papers**, ensuring clarity and readability

Mathfield Demo

Source: https://mathlive.io/mathfield/demo/

Mathfield Demo

<style>{` textarea { font-size: 1em; color: var(--ui-color); background: var(--ui-background); overflow: auto; resize: vertical; vertical-align: top; width: 100%; } .markdown h4 { margin: 0; padding: 0; } math-field, #latex { border-radius: 8px; border: var(--ui-border); padding: 8px; } math-field { font-size: 24px; width: 100%; /* The position and z-index are required to prevent some elements (like a readmore) to be displayed on top of elements of the mathfield. That's an issue in particular with the contextmenu which extends outside the boundary of the mathfield */ position: relative; z-index: 1; } /* math-field:focus-within { outline: Highlight auto 1px; outline: -webkit-focus-ring-color auto 1px } */ #latex { margin-top: 1em; font-family: var(--monospace-font-family), 'Berkeley Mono', 'JetBrains Mono', 'IBM Plex Mono', 'Fira Code', monospace; } pre.console { display: block; max-height: 50vh; padding: 8px 8px 8px 1em; border-radius: 8px; overflow: auto; font-family: var(--monospace-font-family),'Berkeley Mono', 'JetBrains Mono', 'IBM Plex Mono', 'Fira Code', monospace; font-size: 1em; color: var(--base-05); background: var(--base-00); white-space: pre-wrap; border: var(--ui-border, 1px solid rgba(0, 0, 0, .2)); } .console .sep { color: var(--base-05); } .console .index { color: var(--base-05); opacity: .3; float: left; width: 0; font-style: italic; } .console .boolean { color: var(--base-0e); font-weight: bold; } .console .empty { color: var(--base-0e); font-style: italic; } .console .null { color: var(--base-0e); font-style: italic; } .console .string { color: var(--base-0a); font-weight: bold; } .console .function { color: var(--base-0b); } .console .number { color: var(--base-0e); } .console .property { color: var(--base-0b); } .console .object { color: var(--base-0b); } .console .error { display: block; width: calc(100% - 10px); padding-right: 4px; padding-top: 8px; padding-bottom:8px; padding-left: 6px; background: rgba(204, 102, 102, .4); color: white; border-left: 4px solid var(--semantic-red); } .console .warning { color: var(--semantic-orange); } .console .log { color: var(--blue--200); } .console .group { font-weight: bold; } div.shortcuts { display: flex; flex-wrap: wrap; gap: .5em; font-size: 1.5rem; } .shortcuts .cell { display: flex; flex-flow: column; gap: 4px; width: 220px; height: 160px; font-size: .8rem; align-items: center; justify-content: center; border-radius: 8px; border: 1px solid var(--table-thin-line-color); background: var(--card-background--alternate); } .if-glyphs, .if-not-glyphs { display: none !important; visibility: hidden; } body.glyphs .if-glyphs, body:not(.glyphs) .if-not-glyphs { display: inherit !important; visibility: visible; } .shortcuts .label { color: var(--neutral-400); font-weight: 600; text-align: center; } .shortcuts .result { display: flex; align-items: center; justify-content: center; font-size: 24px; min-height: 50px; color: var(--text-color); } .shortcuts .shortcut { display: flex; flex-flow: row; font-size: 18px; font-weight: 600; } .shortcuts .shortcut kbd { align-items: center; justify-content: center; min-width: 28px; margin-left: 1px; margin-right: 1px; font-family: var(--ui-font-family); font-variant-ligatures: none; font-weight: 600; font-size: .8rem; text-align: center; } #result-section { display: none; } #result-section.is-visible { display: block; } #result { margin-left: 8px; font-size: 24px; overflow-x: auto; } `}</style>

import { useEffect } from 'react'; import ErrorBoundary from '@site/src/components/ErrorBoundary';

export function MathfieldDemo({children}) { const INDENT = ' ';

/**

  • Convert a basic type or an object into a HTML string */ function asString( depth, value, options = {} ){ options.quote ??= '"'; options.ancestors ??= [];
//
// BOOLEAN
//
if (typeof value === 'boolean') {
  return {
    text: `<span class="boolean">${escapeHTML(String(value))}</span>`,
    itemCount: 1,
    lineCount: 1,
  };
}

//
// NUMBER
//
if (typeof value === 'number') {
  return {
    text: `<span class="number">${escapeHTML(String(value))}</span>`,
    itemCount: 1,
    lineCount: 1,
  };
}
//
// STRING
//
if (typeof value === 'string') {
  if (options.quote.length === 0) {
    return {
      text: escapeHTML(value),
      itemCount: 1,
      lineCount: value.split(/\r\n|\r|\n/).length,
    };
  }
  return {
    text: `<span class="string">${escapeHTML(
      options.quote + value + options.quote
    )}</span>`,
    itemCount: 1,
    lineCount: value.split(/\r\n|\r|\n/).length,
  };
}

//
// FUNCTION
//
if (typeof value === 'function') {
  let functionValue = '';
  if ('toString' in value) functionValue = escapeHTML(value.toString());
  else functionValue = escapeHTML(String(value));

  return {
    text: `<span class="function">ƒ  ${functionValue}</span>`,
    itemCount: 1,
    lineCount: functionValue.split(/\r\n|\r|\n/).length,
  };
}

//
// NULL/UNDEFINED
//
if (value === null || value === undefined) {
  return {
    text: `<span class="null">${escapeHTML(String(value))}</span>`,
    itemCount: 1,
    lineCount: 1,
  };
}

// Avoid infinite recursions (e.g. `window.window`)
if (depth > 20) {
  return {
    text: '<span class="sep">(...)</span>',
    itemCount: 1,
    lineCount: 1,
  };
}

//
// ARRAY
//
if (Array.isArray(value)) {
  if (options.ancestors.includes(value))
    return {
      text: '<span class="sep">[...]</span>',
      itemCount: 1,
      lineCount: 1,
    };

  const result = [];
  // To account for sparse array, we can't use map() (it skips over empty slots)
  for (let i = 0; i < value.length; i++) {
    if (Object.keys(value).includes(Number(i).toString())) {
      result.push(
        asString(depth + 1, value[i], {
          ancestors: [...options.ancestors, value],
        })
      );
    } else {
      result.push({
        text: '<span class="empty">empty</span>',
        itemCount: 1,
        lineCount: 1,
      });
    }
  }
  const itemCount = result.reduce((acc, val) => acc + val.itemCount, 0);
  const lineCount = result.reduce(
    (acc, val) => Math.max(acc, val.lineCount),
    0
  );
  if (itemCount > 5 || lineCount > 1) {
    return {
      text:
        "<span class='sep'>[</span>\n" +
        INDENT.repeat(depth + 1) +
        result
          .map((x, i) => '<span class="index">' + i + '</span>' + x.text)
          .join("<span class='sep'>, </span>\n" + INDENT.repeat(depth + 1)) +
        '\n' +
        INDENT.repeat(depth) +
        "<span class='sep'>]</span>",
      itemCount,
      lineCount: 2 + result.reduce((acc, val) => acc + val.lineCount, 0),
    };
  }
  return {
    text:
      "<span class='sep'>[</span>" +
      result.map((x) => x.text).join("<span class='sep'>, </span>") +
      "<span class='sep'>]</span>",
    itemCount: Math.max(1, itemCount),
    lineCount: 1,
  };
}

//
// HTMLElement
//
if (value instanceof Element) {
  if (options.ancestors.includes(value))
    return {
      text: '<span class="object">Element...</span>',
      itemCount: 1,
      lineCount: 1,
    };

  let result = `<${value.localName}`;
  let lineCount = 1;
  Array.from(value.attributes).forEach((x) => {
    result +=
      ' ' + x.localName + '="' + value.getAttribute(x.localName) + '"';
  });
  result += '>';

  if (value.innerHTML) {
    let content = value.innerHTML.split('\n');
    if (content.length > 4) {
      content = [...content.slice(0, 5), '(...)\n'];
    }
    result += content.join('\n');
    lineCount += content.length;
  }

  result += `</${value.localName}>`;
  return {
    text: `<span class="object">${escapeHTML(result)}</span>`,
    itemCount: 1,
    lineCount: lineCount,
  };
}

//
// OBJECT
//
if (typeof value === 'object') {
  if (options.ancestors.includes(value))
    return {
      text: '<span class="sep">{...}</span>',
      itemCount: 1,
      lineCount: 1,
    };

  if (value instanceof Map) {
    const kv = Object.fromEntries(value);
    const result = asString(depth, kv, {
      ancestors: [...options.ancestors, value],
    });
    return { ...result, text: '<span class=object>Map</span>' + result.text };
  }
  if (value instanceof Set) {
    const elts = Array.from(value);
    const result = asString(depth, elts, {
      ancestors: [...options.ancestors, value],
    });
    return { ...result, text: '<span class=object>Set</span>' + result.text };
  }

  if ('toString' in value) {
    const s = value.toString();
    if (s !== '[object Object]')
      return {
        text: escapeHTML(s),
        itemCount: 1,
        lineCount: 1,
      };
  }
  let props = Object.keys(value);

  Object.getOwnPropertyNames(value).forEach((prop) => {
    if (!props.includes(prop)) {
      props.push(prop);
    }
  });
  props = props.filter((x) => !x.startsWith('_'));
  if (props.length === 0 && typeof props.toString === 'function') {
    const result = value.toString();
    if (result === '[object Object]')
      return {
        text: '<span class="sep">{}</span>',
        itemCount: 1,
        lineCount: 1,
      };
    return {
      text: result,
      itemCount: 1,
      lineCount: result.split(/\r\n|\r|\n/).length,
    };
  }

  const propStrings = props.sort().map((key) => {
    if (typeof value[key] === 'object' && value[key] !== null) {
      let result = asString(depth + 1, value[key], {
        ancestors: [...options.ancestors, value],
      });
      if (result.itemCount > 500) {
        result = {
          text: "<span class='sep'>(...)</span>",
          itemCount: 1,
          lineCount: 1,
        };
      }
      return {
        text: `<span class="property">${key}</span><span class='sep'>: </span>${result.text}`,
        itemCount: result.itemCount,
        lineCount: result.lineCount,
      };
    }
    if (typeof value[key] === 'function') {
      return {
        text: `<span class="property">${key}</span><span class='sep'>: </span><span class='function'>ƒ (...)</span>`,
        itemCount: 1,
        lineCount: 1,
      };
    }
    const result = asString(depth + 1, value[key], {
      ancestors: [...options.ancestors, value],
    });
    return {
      text: `<span class="property">${key}</span><span class='sep'>: </span>${result.text}`,
      itemCount: result.itemCount,
      lineCount: result.lineCount,
    };
  });
  const itemCount = propStrings.reduce((acc, val) => acc + val.itemCount, 0);
  const lineCount = propStrings.reduce((acc, val) => acc + val.lineCount, 0);
  if (itemCount < 5) {
    return {
      text:
        "<span class='sep'>{</span>" +
        propStrings
          .map((x) => x.text)
          .join("</span><span class='sep'>, </span>") +
        "<span class='sep'>}</span>",
      itemCount,
      lineCount,
    };
  }
  return {
    text:
      "<span class='sep'>{</span>\n" +
      INDENT.repeat(depth + 1) +
      propStrings
        .map((x) => x.text)
        .join(
          "</span><span class='sep'>,</span>\n" + INDENT.repeat(depth + 1)
        ) +
      '\n' +
      INDENT.repeat(depth) +
      "<span class='sep'>}</span>",
    itemCount: itemCount,
    lineCount: lineCount + 2,
  };
}
return { text: String(value), itemCount: 1, lineCount: 1 };

}

function escapeHTML(s) { return s .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); }

const onMathfieldUpdate = (mf) => { // The ref callback is called with null when the element unmounts if (mf === null) return; const latexField = document.getElementById('latex'); if (!latexField) return; latexField.value = mf.value; const expr = mf?.expression; // Output MathJSON representation of the expression document.getElementById('math-json').innerHTML = expr ? asString(0, expr.json).text : '😕 The Compute Engine is not available'; if (!expr) return;

let result = '';

if (typeof MathfieldElement !== 'undefined' && MathfieldElement.computeEngine) {
  MathfieldElement.computeEngine.precision = 7;
}

if (expr.head !== 'Equal') {
  const exprN = expr.N();

  if (!exprN.isSame(expr)) result = exprN.latex;
}

if (!result) {
  const exprSimplify = expr.simplify();
  if (!exprSimplify.isSame(expr)) result = exprSimplify.latex;
}

if (expr.head !== 'Equal') {
  if (!result) {
    const exprEval = expr.evaluate();
    if (!exprEval.isSame(expr)) result = exprEval.latex;
  }
}

if (result) {
  const markup = window.MathLive?.convertLatexToMarkup?.('= ' + result);
  if (markup) {
    document.getElementById('result').innerHTML = markup;
    document.getElementById('result-section').classList.add('is-visible');
  } else {
    document.getElementById('result-section').classList.remove('is-visible');
  }
} else {
  document.getElementById('result-section').classList.remove('is-visible');
}

};

const onInput = (evt) => onMathfieldUpdate(evt.target);

useEffect(() => { const latexField = document.getElementById('latex'); latexField.value = children; }, [])

// There's a bug somewhere (React?) where return <math-field/> doesn't work // (the JSX code produced is invalid). Calling the _jsx function directly // works around the issue. return _jsx('math-field', { onInput, ref: (node) => onMathfieldUpdate(node), value: children }); }

{`x=\\frac{-b\\pm \\sqrt{b^2-4ac}}{2a}`}
Read more about using the **Compute Engine** to evaluate and simplify expression.

LaTeX

<textarea id="latex" onInput={() => { const mf = document.querySelector('math-field'); mf.value = document.getElementById('latex').value; }}></textarea> Read more about the supported **LaTeX commands**.

MathJSON



Learn more about MathJSON and try a demo of the **Compute Engine**.

Keyboard Shortcuts

{`$$ \\frac{\\blacksquare}{\\blacksquare}$$`}
Fraction
/
{`$$ \\square^\\blacksquare$$`}
Superscript, Power
^
+6
SHIFT+6
{`$$\\square_\\blacksquare$$`}
Subscript
_
{`$$\\sqrt{\\blacksquare}$$`}
Square root
+ V
ALT + V
{`$$\\int^{\\blacksquare}_{\\blacksquare}$$`}
Integral
+ B
ALT + B
{`$$\\sum$$`}
Sum
+ W
ALT + W
{`$$\\prod^\\blacksquare_\\blacksquare$$`}
Product
+ + P
ALT + SHIFT + P
{`$$ \\pi$$`}
Pi
PI
{`$$ \\infty$$`}
Infinity
OO
{`$$ \\pm$$`}
Plus or minus
+-
{`$$ \\mathbb{R}$$`}
Blakckboard R
+R+R
SHIFT+RSHIFT+R
Enter/exit LaTeX mode
ESC
Enter/exit text mode
"
+'
SHIFT+'
Read more about all the available **keybindings** and **shortcuts**.

export default function ({children}) { useEffect(() => { const platform = navigator['userAgentData']?.platform ?? navigator.platform; const isApple = /^mac/i.test(platform) || /iphone|ipod|ipad/i.test(navigator.userAgent);

// The body class gets cleared when the page is reloaded, so we need to
// set it again after a short delay.
if (isApple) 
  setTimeout(() => document.body.classList.add('glyphs'), 16);

// Restore the body class when the page is reloaded
return () => document.body.classList.remove('glyphs');

}, []); return <>{children}</>; }


Math Virtual Keyboard

Source: https://mathlive.io/mathfield/virtual-keyboard/

Typing math requires access to many special symbols. While [keyboard shortcuts and inline shortcuts](/mathfield/guides/shortcuts) can help when a physical keyboard is available, touch-enabled devices without a physical keyboard attached need another solution.

The math virtual keyboard is a keyboard displayed on screen that gives access to specialized symbols for math input with only a tap.

Layout Selector

The math keyboard includes multiple layouts which can be chosen with the layout selector.

The default layouts include the most common math symbols. They are: numeric, symbols, alphabetic and greek letters.

These layouts can be customized to fit specific needs. Learn more about **customizing virtual keyboards**.

Undo/Redo/Paste

The Editing Toolbar display icons for common editing functions: Undo, Redo, Paste, Cut and Copy.

If you have a physical keyboard attached, these commands can be invoked with their corresponding keybindings: Ctrl/Command+Z, Ctrl/Command+Y, Ctrl/Command+V, Ctrl/Command+X and Ctrl/Command+C.

Shift Key

Press the Shift Key to access alternative symbols. The keyboard updates when the key is pressed to reveal the symbols.

If a physical keyboard is available, the SHIFT or CAPSLOCK key on the physical keyboard can also be used.

The symbol corresponding to the shifted variant is displayed in the top right corner of some keys. Some keys have a shifted variant even though they may not include a top-right label.

Variants

A key variant is a symbol that can be accessed by a long press on a keycap. The variant is often related to the original symbol.

To display variants related to a keycap, press and hold the keycap.

Many keycaps have variants, but a few don't.

Numeric Layout

Numeric Keyboard

Numeric Keyboard

Numeric Keyboard, shifted

Symbols Layout

Symbols Keyboard

Symbols Keyboard, shifted

Alphabetic Layout

Greek Layout


Matrix Editor

Source: https://mathlive.io/mathfield/matrix/

A matrix is a useful way to represent and manipulate linear transformations. They are also used to represent systems of linear equations and many other mathematical structures.

Mathfields can display and edit matrices in a variety of ways.

Creating a Matrix

There are several methods to create a matrix in a mathfield.

Using Keyboard Shortcuts

To create a matrix using the keyboard:

  1. Type a parenthesis, square bracket, or curly brace.
  2. Type the first element of the matrix.
  3. Type the ALT/OPTION+TAB key to move to the next column: this will automatically transform the expression into a matrix
  4. Type the ALT/OPTION+RETURN key to move to the next row.

Using the Context Menu

The mathfield context menu provides a convenient way to create a matrix.

To access the context menu right click (or CTRL+click) on the mathfield. The menu is also available by typing ALT+SPACE, or by tapping on the menu button in the mathfield.

To insert a matrix using the context menu select the Insert Matrix menu, then select the number of rows and columns of the matrix.

Matrix Borders

The borders of a matrix are parentheses by default. They can be changed to square brackets, curly braces, vertical bars, or none.

To change the border of a matrix right click (or CTRL+click) on the matrix, then select the desired border from the Matrix Border menu.

In LaTeX, matrices are represented using the \\begin\{\}...\\end\{\} syntax. The argument to the begin command determines the type of matrix and is called the environment.

Inside the environment, the matrix is specified using the & character to separate columns and the \\\\ character to separate rows.

The following environments are supported:

Environment Description
matrix A matrix with no delimiters
pmatrix A matrix surrounded by parentheses
bmatrix A matrix surrounded by square brackets
Bmatrix A matrix surrounded by curly braces
vmatrix A matrix surrounded by vertical bars
Vmatrix A matrix surrounded by double vertical bars
smallmatrix A matrix with no delimiters, in a smaller font
array A matrix with no delimiters, with control over column alignment

{\\begin\{matrix\} a & b \\\\ c & d \\end\{matrix\}}

{\\begin\{pmatrix\} a & b \\\\ c & d \\end\{pmatrix\}}

{\\begin\{bmatrix\} a & b \\\\ c & d \\end\{bmatrix\}}

{\\begin\{Bmatrix\} a & b \\\\ c & d \\end\{Bmatrix\}}

{\\begin\{vmatrix\} a & b \\\\ c & d \\end\{vmatrix\}}

{\\begin\{Vmatrix\} a & b \\\\ c & d \\end\{Vmatrix\}}

{\\begin\{smallmatrix\} a & b \\\\ c & d \\end\{smallmatrix\}}

{\\begin\{array\}\{cc\} a & b \\\\ c & d \\end\{array\}}

Changing the Shape of a Matrix

To add or remove rows or columns right click (or CTRL+click) on the matrix, then select the desired action from the menu. Rows and columns get added or removed relative to the cell the cursor is in.

Spacing

Changing the spacing of an individual row

The spacing between rows can be adjusted by setting an optional argument to the \\\\ command. The argument is a length, and can be positive or negative.

For example, the following matrix has no space between columns and a double space between rows:

{\\begin\{pmatrix\} a & b \\\\[1.5em] c & d \\end\{pmatrix\}}

Units can be specified using the following abbreviations:

  • em (the width of the letter M in the current font)
  • mu (math unit, 1/18 em)
  • ex (the height of the letter x in the current font)
  • pt (a point, 1/72.27 inch)
  • pc (a pica, 12 points)
  • px (a pixel, 1/96 inch)
  • cm (a centimeter)
  • mm (a millimeter)
  • in (an inch)
  • bp (a big point, 1/72 inch)
  • dd (a didot point, 1238/1157 mm)
  • cc (a cicero, 12 didot points)
  • sp (a scaled point, 65536 sp = 1 pt)

Changing the spacing of all rows

The spacing between rows can be controlled by setting the arraystretch register. The default value is 1.0.

The value of a register can also be modified by using the \renewcommand command. In general, modifying registers using mf.registers is preferred, but using \renewcommand might be handy, for example when rendering static LaTeX.

mf.registers.arraystretch = 2.5

{\\renewcommand\{\\arraystretch\}\{2.5\} \\begin\{pmatrix\} a & b \\\\ c & d \\end\{pmatrix\}}

{\\renewcommand\{\\arraystretch\}\{0.5\} \\begin\{pmatrix\} a & b \\\\ c & d \\end\{pmatrix\}}


LaTeX Commands

Source: https://mathlive.io/mathfield/reference/commands/

Mathfields support over **800** LaTeX commands. **To find the name of the LaTeX command matching the shape of a symbol you can draw**, use **Detexify**

To enter a LaTeX command in mathfield press the ESC key or \
to enter LaTeX editing mode. Press ESC to exit LaTeX editing mode.

To examine the LaTeX code for an expression, select it, then press ESC.

The most common symbols can be entered using **keyboard shortcuts**.

Text Zone, Math Zone and Math Style

Math Zone

When in a Math Zone, the content is laid out using typesetting rules specific to math.

For example, variables such as $x$ are displayed in italics, an appropriate amount of space is inserted around some letters such as $ f $ to improve their legibility, and white spaces are ignored.

In a Math Zone, the layout and size of some math elements is adjusted based on the context in which they are used. For example, superscripts and subscripts are displayed using a smaller font size: $ 2^2 $.

Inside a Math Zone, the Math Style indicate the size of the font used to display the content, and some layout options, such as placement of the limits of a sum or integral.

To override the default Math Style, use the following commands:

Math Style
\displaystyle

For equations in their own paragraph/block
\displaystyle \sum_{i=0}^n \frac{a_i}{1+x} $$\displaystyle \sum_{i=0}^n \frac{a_i}{1+x} $$
\textstyle

Confusingly, for inline math, not for text content
\textstyle \sum_{i=0}^n \frac{a_i}{1+x} $$\textstyle \sum_{i=0}^n \frac{a_i}{1+x} $$
\scriptstyle

For subscripts and superscripts
\scriptstyle \sum_{i=0}^n \frac{a_i}{1+x} $$\scriptstyle \sum_{i=0}^n \frac{a_i}{1+x} $$
\scriptscriptstyle

For subscripts and superscripts of subscripts and superscripts
\scriptscriptstyle \sum_{i=0}^n \frac{a_i}{1+x} $$\scriptscriptstyle \sum_{i=0}^n \frac{a_i}{1+x} $$

Text Zone

To include some textual content, use the \text{} or \textrm{} commands to switch to a Text Zone. Inside a Text Zone, white spaces are preserved and the spacing of characters is not adjusted.

The \text{} command will use the font defined by the CSS font-family property of the enclosing mathfield. The size of the text will adjust depending on the current math style (smaller in superscript/subscript).


The \textrm{} command works like \text{} but will use a serif (roman) font.


The \mbox{} command uses the same font as \text but its size does not account for the current math style.


The \textnormal{} command works like \text{}. But it's longer to type.

When in a Text Zone, use $...$ to switch back to an Inline Math Zone or \\[...\\] to switch to a Display (block) Math Zone.

Fractions and Binomials

The \frac command is used to represent a fraction. The first argument is the numerator, the second argument is the denominator. It will size itself according to the current math style (display, text (inline), script, scriptscript). The \dfrac and \tfrac commands force the math style to be display or text (inline) style respectively.

The \cfrac (continuous fraction) command has an optional argument, [l] or [r], that controls if the numerator is left-aligned or right-aligned.

The \pdiff command is a convenient shortcut for partial differentials.


The \binom command is used to represent a binomial coefficient. The \dbinom and \tbinom commands force the math style to be display or text (inline) style respectively.

:::warning[Deprecated]

The following commands are supported but their usage is generally discouraged when creating modern LaTeX content.

:::

Binary Operators

Some binary operators can also be used as a unary operator: +, -, etc... Their spacing is adjusted accordingly. For example in \( -1-2 \) there is less space between - and 1 than there is between - and 2.




Functions

Trigonometry

Non-Standard Trig Functions

The commands in this section are not part of the standard LaTeX distribution but are available in some packages. Use them with caution as they may not be supported by all LaTeX engines. Consider using \operatorname{} instead.

Bounds

Projections

Modulo

Custom Functions

To define a custom function use the \operatorname{} command: the name of the function will be displayed in upright font and with the appropriate spacing.

Unicode

If a symbol is not available as a LaTeX command, you can use the Unicode codepoint of the character. The commands below can be used to insert a Unicode character in a mathfield.

Command
\unicode{} The argument is a Unicode codepoint expressed as a number. To use a hexadecimal number, start the argument with x or " and use uppercase A-F for hexadecimal digits.
  • $$\Large\unicode{10775} $$ \unicode{10775}
  • $$\Large\unicode{"2A17}$$ \unicode{"2A17}
  • $$\Large\unicode{x2A17}$$ \unicode{x2A17}
\char The argument is also a Unicode codepoint, but the {...} delimiters are optional when using ".
  • $$\Large\char"2A17 $$ \char"2A17
^^
^^^^
Followed by 2 or 4 hexadecimal digits with lowercase a-f to specify a Unicode codepoint.
  • $$\Large^^4a $$ ^^4a
  • $$\Large^^^^2a17 $$ ^^^^2a17

:::info[Note] The codepoint of the Unicode character ⨗ U+2A17 INTEGRAL WITH LEFTWARDS ARROW WITH HOOK is 10775 in decimal, 2A1716 in hexadecimal. The codepoint of the letter J is 004A16 in hexadecimal. Learn more about Mathematical Operators and Symbols in Unicode on Wikipedia. :::

Large Operators

Large operators display their limits above and below or adjacent to the operator, depending on the math style (Display Style or Text Style) and on the operator.

The position of the limits can be controlled with \limits, \nolimits or \displaylimits after the operator. The \limits command forces the display of the limits above and below the operator, \nolimits forces the display of the limits adjacent to the operator, and \displaylimits uses an automatic position, based on the operator and current math style.

\limits \nolimits \displaylimits
$$\sum_{i=0}^n\limits $$ $$\sum_{i=0}^n\nolimits $$ $$\sum_{i=0}^n\displaylimits $$
\sum_{i=0}^n\limits \sum_{i=0}^n\nolimits \sum_{i=0}^n\displaylimits
$$\int_0^\infty\limits $$ $$\int_0^\infty\nolimits $$ $$\int_0^\infty\displaylimits $$
\int_0^\infty\limits \int_0^\infty\nolimits \int_0^\infty\displaylimits

In Display Style, the \intop and \ointop commands display their limits above and below by default, while the \int command display its limit adjacent.


Logic

Quantifiers

Unary/Binary Operators

Relational Operators

Arrows

Negated Arrows

Extensible Arrows

The length of the arrow commands above is fixed. The length of the commands in this section is determined by the length of the content above and below the arrows, which is specified as an argument (and optional argument):

<Latex value='\xrightarrow[\text{long text below}]{}'flow='column'/> <Latex value='\xrightarrow{\text{long text above}}'flow='column'/> <Latex value='\xrightarrow[\text{and below}]{\text{long text above}}'flow='column'/>