date | title | slug |
---|---|---|
Last Modified |
Customizing a Mathfield |
/mathfield/guides/customizing/ |
In this section we'll go over some of the ways a mathfield can be customized.
To style the mathfield define a CSS rule targeting the mathfield or use the
style
attribute of the <math-field>
element.
CSS attributes can be used to modify the appearance of the mathfield in many ways, for example changing the base font size or adding a border around it.
To remove the border around the mathfield, set the
border
property to none
or 0
.
To change the background color of the mathfield, use the background
property.
:::html
<math-field style="border: none; background: #d8f0ff">
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
To display the mathfield as a block element, rather than an inline element,
add an attribute style="display: block"
:::html
<p>Answer:
<math-field style="font-size:1.2rem">42</math-field>.
</p>
<p>Answer:
<math-field style="font-size:2rem; display: block">3.1415</math-field>
</p>
To customize the appearance of the mathfield, use the following CSS variables (custom properties) in a ruleset that applies to the mathfield element.
math-field {
--smart-fence-color: red ;
}
Although CSS styles are "invisible" to custom components, CSS variables are
"passed through" and will affect the content of the <math-field>
custom component.
Set these CSS variables on any selector that applies to the
<math-field>
element you want to customize, for example, body
.
Alternatively these CSS variables programatically can be set programmatically:
document.body.style.setProperty("--smart-fence-color", "red");
CSS Variable | Usage |
---|---|
--primary |
Primary accent color, used for example keyboard toggle and menu glyphs and in the virtual keyboard |
--caret-color |
Color of the insertion point |
--selection-color |
Color of the content when selected |
--selection-background-color |
Background color of the selection |
--contains-highlight-background-color |
Background color of items that contain the caret |
--placeholder-color |
Color of the placeholder symbol |
--placeholder-opacity |
Opacity (0-1) of the placeholder symbol |
--smart-fence-color |
Color of a smart fence (default is current color) |
--smart-fence-opacity |
Opacity of a smart fence (default is 50% ) |
--highlight-text |
The background color indicating the caret is in a text zone |
--text-font-family |
The font stack used for content in a text zone |
--latex-color |
The color of content in a LaTeX zone |
--correct-color |
Highlight color of a prompt when in the "correct" state |
--incorrect-color |
Highlight color of a prompt when in the "incorrect" state |
For color values, you can use any valid CSS color value, such as a color name, or `transparent to remove the color.
Note To change the placeholder symbol, use the mf.placeholderSymbol
property.
:::html
<style>
math-field {
--caret-color: red;
--selection-background-color: lightgoldenrodyellow;
--selection-color: darkblue;
}
</style>
<math-field>
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
You can customize the appearance and zindex of the virtual keyboard panel with some CSS variables associated with a selector that applies to the virtual keyboard panel container.
Read more about customizing the virtual keyboard appearance
Because the mathfield is a custom element with a shadow DOM, its content is not directly accessible to CSS rules outside of the shadow DOM.
However, there are a few parts that can be used to style the
content of the mathfield using the ::part()
pseudo-element.
Pseudo-element | Usage |
---|---|
virtual-keyboard-toggle |
The virtual keyboard toggle button |
menu-toggle |
The menu toggle button |
content |
The math formula |
container |
The element containing the formula, the keyboard toggle and the menu toggle |
keyboard-sink |
The hidden element capturing the physical keyboard input |
placeholder |
The element containing the placeholder attribute when the mathfield is empty |
prompt |
The prompts (placeholder{} ) inside the mathfield |
For example:
/* Right align the formula */
math-field::part(content) {
text-align: right;
}
/* Right align the virtual keyboard toggle */
math-field::part(container) {
flex-flow: row-reverse;
}
/* Hide the virtual keyboard toggle */
math-field::part(virtual-keyboard-toggle) {
display: none;
}
/* Hide the menu toggle */
math-field::part(menu-toggle) {
display: none;
}
Note When the menu toggle is hidden, the menu can still be opened by right-clicking on the mathfield. You can customize the menu to change this behavior.
To customize the placeholder text set the placeholder
attribute on the
<math-field>
element.
Note that the content of the placeholder
attributed is interpreted as a
LaTeX string. To display it as regular text, use the \text{}
command.
:::html
<math-field placeholder="\text{Enter a formula}">
</math-field>
To change the appearance of the focus ring, use the :focus-within
pseudo-element.
:::html
<style>
math-field:focus-within {
outline: 4px solid #d7170b;
border-radius: 4px;
background: rgba(251, 187, 182, .1);
}
</style>
<math-field>
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
:::warning
Caution Removing outlines in CSS creates issues for people navigating the web with a keyboard. However, you can change the appearance of the outline, for example to indicate an error condition. If you remove the outline on the mathfield, make sure to replace it with another indicator, for example by displaying an outline on an enclosing element.
:::
The appearance of a formula, in an editable mathfield or as a static representation, can be controlled with some of the following options:
To change the foreground ("ink") and background ("paper") colors of a formula
programmatically, use the mf.applyStyle()
function.
To change the foreground color, use the \textcolor{}{}
command.
To change the background color, use the \colorbox{}{}
command.
The first argument of these commands is a color specified as:
- a RGB color using the standard CSS format (
#d7170b
) - a CSS color name (
goldenrod
) - one of the 68 colors from dvips color name (
cadetblue
) - one of the 10 Mathematica color from
ColorData[97, "ColorList"]
(m0
tom9
) - a color defined using the syntax from the
xcolor
package, for example:blue!20!black!30!green
The following color names are recommended. They can be applied using the color keys in the virtual keyboard:
:::info[Note]
These colors have been carefully selected for a balanced representation of the range of
hues on the color circle, with similar lightness and intensity. They will map to different color values than the dvips
colors of the same name.
:::
:::info[Note]
To have proper legibility based on usage, these color names will map to different values when used as a foreground color and a background color. To use a specific color value, use a RGB color instead.
:::
:::info[Note]
To customize how the color names are interpreted provide a colorMap
or backgroundColorMap
function.
:::
To change the base font size, set the font-size
CSS property to the desired
value on the mathfield
or static element.
Within a formula, the size can be specified from a font scale with 10 values, where 1 em is the base font size of the mathfield or static element.
fontSize |
LaTeX Command | |
---|---|---|
1 | 0.5 em | \tiny |
2 | 0.7 em | \scriptsize |
3 | 0.8 em | \footnotesize |
4 | 0.9 em | \small |
5 | 1 em | \normalsize or \normal |
6 | 1.2 em | \large |
7 | 1.44 em | \Large |
8 | 1.728 em | \LARGE |
9 | 2.074 em | \huge |
10 | 2.488 em | \Huge |
:::warning
In TeX, the sizing commands behave inconsistently when applied to math. Other implementations of TeX may also interpret the sizing commands differently.
:::
To control some aspects of the math typesetting, change the mathstyle with
the commands \displaystyle
, \textstyle
, \scriptstyle
, \scriptscriptstyle
.
The displaystyle
style is most appropriate when there is plenty of space around
the formula. Limits over large operators, such as \sum
are displayed above
and below the operator. There is a generous amount of space below the numerator
and above the denominator of fractions, and around relational (=
) and binary
(+
) operators.
The textstyle
style is useful when space is constrained or when displaying
a formula with some regular text around it. The limits of large operators
are displayed after the operator. The numerator and denominator of fractions is
displayed using a smaller font size. However, the font-size for other characters
is not affected.
The scriptstyle
and scriptscriptstyle
are rarely needed explicitly. The
content is laid out using a smaller font-size (70% and 50% of the base font-size,
respectively) and the spacing between operators is minimized. Note however
that these styles are used automatically in some situations. For example,
when using the displaystyle
or textstyle
, the limits of a large operator
or the superscript or subscript of a symbol are displayed using these styles.
Notice for example that n=0
in displaystyle
does not include space around
the =
sign because the limit is displayed in scriptstyle
.
To set the default mathstyle of a mathfield, set the mf.defaultMode
property or the default-mode
attribute.
Set it to "inline-math"
to use textstyle
or "math"
to use displaystyle
.
:::html
<p>The answer is
<math-field default-mode="inline-math">
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>.
</p>
By default, the mathfield element is laid out on the page as an inline element
when in an inline context (when inside a <p>
tag for example).
To get it laid out as a block element, set display: block
on the mathfield.
To control which letters are automatically italicized, set the letterShapeStyle
property or letter-shape-style
attribute.
letterShapeStyle |
xyz | ABC | αβɣ | ΓΔΘ |
---|---|---|---|---|
iso |
xyz | ABC | αβɣ | ΓΔΘ |
tex |
xyz | ABC | αβɣ | ΓΔΘ |
french |
xyz | ABC | αβɣ | ΓΔΘ |
upright |
xyz | ABC | αβɣ | ΓΔΘ |
In the ISO style, lower and uppercase roman letter and lower and upper case greek letters are italicized when used as a variable. Mathematical constants such as \(e\) are written upright.
TeX has traditionally implemented a layout option that italicizes romman letters and lowercase greek letters, but not uppercase greek letters.
The French typographical convention is to only italicize lowercase roman letters.
The default letter shape style is auto
: if the system locale is "french",
the french
style is used, otherwise tex
is used.
The editing behavior of a mathfield can be customized by setting some
properties on the mathfield, or the equivalent attributes on the
<math-field>
tag.
defaultMode
:"inline-math"
: use inline math mode"math"
: use the display math mode"text"
: use the text mode |
removeExtraneousParentheses
: automatically remove extra parentheses around a numerator or denominatorscriptDepth
: maximum levels of subscript or superscript. Set it to 0 to prevent the input of superscript and subscriptssmartFence
: automatically convert parentheses to\left...\right
markup.smartMode
: switch to text mode when text input is detected, for example when typing "if x > 0"smartSuperscript
: automatically move out of a superscript when a digit is typed
These properties can also be passed as an argument to new MathfieldElement()
when programmatically creating mathfield elements.
In the interactive code playground below, try some of these options. For example,
in line 1 add the attribute smart-mode=false
, then type some parentheses
in the mathfield.
:::html
<math-field smart-mode>
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
See `EditingOptions` for more details about these and other available options
In traditional math typesetting, spaces have no effect: the spacing of elements in a formula is determined by the nature of the elements: numbers, punctuation, relational, binary or unary operators, etc...
To control spacing in a formula, use some of the LaTeX spacing commands: \quad
,
\qquad
, \!
, \,
(thin space), \:
(medium space), \;
(thick space), \enskip
or \enspace
.
By default, pressing the spacebar when in math mode does not insert anything.
To insert a LaTeX command when the spacebar is pressed, set the value of the
mathModeSpace
property to that command:
mf.mathModeSpace = '\\:';
Pressing the \ (backslash) or ESC key switches to the LaTeX mode where it is possible to enter raw LaTeX command. For users familiar with LaTeX, it is a powerful way to enter or edit LaTeX in an expression. However, users unfamiliar with LaTeX may be confused if they accidentally press those keys.
To prevent the LaTeX mode from being enabled intercept the trigger keys and call `preventDefault().
mf.addEventListener(
'keydown',
(ev) => {
if (ev.key === '\\') {
ev.preventDefault();
mf.executeCommand(['insert', '\\backslash']);
} else if (ev.key === 'Escape') ev.preventDefault();
},
{ capture: true }
);
The user interface of the mathfield is provided in english, arabic, german, greek, spanish, farsi, french, italian, japanese, polish and russian.
The language to use is detected automatically, but it can be overridden by
using the MathfieldElement.locale
static property. Setting this property
will affect all mathfield elements on the page.
:::js
await customElements.whenDefined('math-field');
const locale = MathfieldElement.locale;
console.log("Locale:", locale);
console.log(MathfieldElement.strings[locale.substring(0, 2)]);
:::html
<math-field id=formula>
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
The world is
about evenly split
between using a dot .
or a comma ,
as a decimal marker.
To change the marker used with decimal numbers set the
MathfieldElement.decimalSeparator
property to ","
or "."
.
When set to ","
, pressing the , key on a physical keyboard will insert a
{,}
LaTeX string, if in math mode and if before a digit.
The LaTeX sequence {,}
is traditionally used to correctly typeset the comma
and ensure the correct amount of space around it. Without the {}
, the ,
is interpreted as a delimiter and has excessive amount of space around it.
When set to ","
, the virtual keyboard is also changed so that the .
keycap is labeled ,
instead and contextually inserts a {,}
when appropriate.
:::js
await customElements.whenDefined('math-field');
MathfieldElement.decimalSeparator = ",";
:::html
<math-field id='formula'>
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
When using the arrow keys on the keyboard to navigate a fraction, the order in which the numerator and navigator are traversed can be customized.
To change the keyboard navigation order of fractions set the
MathfieldElement.fractionNavigationOrder
property.
The possible values are:
"numerator-denominator"
: first the elements in the numerator, then the elements in the denominator. This is the default behavior."denominator-numerator"
: first the elements in the denominator, then the elements in the numerator. In some East-Asian cultures, fractions are read and written denominator first (fēnzhī). With this option the keyboard navigation follows this convention.
:::js
await window.customElements.whenDefined('math-field');
MathfieldElement.fractionNavigationOrder = "denominator-numerator";
:::html
<math-field>
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
The mathfield provides some audio feedback when a key is pressed on the virtual keyboard or when an action cannot be performed, for example when trying to delete when the mathfield is empty (the "plonk" sound).
The files for the sounds played by the mathfield should be located in a
directory named sounds
next to the mathfield library. If your bundler or
asset management system require a different configuration you can specify
where the sounds can be located using the MathfieldElement.soundsDirectory
property.
MathfieldElement.soundsDirectory =
"https://cdn.jsdelivr.net/npm/mathlive/sounds/";
Specific sounds can be disabeld or customized with the MathfieldElement.keypressSound
property.
MathfieldElement.keypressSound = {
spacebar: null,
return: "./sounds/return.mp3",
delete: null,
default: null,
}
To play the "plonk" sound when an action cannot be performed, use MathfieldElement.playSound('plonk')
.
MathfieldElement.playSound('plonk');
To turn off the sounds set the MathfieldElement.soundsDirectory
property to null
.
MathfieldElement.soundsDirectory = null;
When a key on the virtual keyboard is pressed, a small vibration is triggered
on devices that support it. This can be turned off by setting the
MathfieldElement.keypressVibration
property to false
.
MathfieldElement.keypressVibration = false;
The content of the mathfield is displayed using a family of high-quality fonts based on the original Computer Modern font from TeX. The mathfield will not display correctly using another font.
By default, the directory containing the fonts is located next to the file
containing the mathlive library. If your bundler or asset management system
require a different configuration you can specify where the fonts can be
located using the MathfieldElement.fontsDirectory
property.
:::style
.output:focus-within {
outline: Highlight auto 1px;
outline: -webkit-focus-ring-color auto 1px
}
.output math-field:focus, .output math-field:focus-within {
outline: none;
}
:::js
await window.customElements.whenDefined("math-field");
MathfieldElement.fontsDirectory = "https://cdn.jsdelivr.net/npm/mathlive/fonts/";
:::html
<math-field>
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
```---
date: Last Modified
title: Matrix Editor
slug: /mathfield/matrix/
toc_max_heading_level: 2
---
<Intro>
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.
</Intro>
## 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 <kbd>ALT/OPTION</kbd>+<kbd>TAB</kbd> key to move to the next column: this will automatically
transform the expression into a matrix
4. Type the <kbd>ALT/OPTION</kbd>+<kbd>RETURN</kbd> 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 <kbd>CTRL</kbd>+click) on the
mathfield. The menu is also available by typing <kbd>ALT</kbd>+<kbd>SPACE</kbd>,
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 <kbd>CTRL</kbd>+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 |
---
<Latex flow="column">{`
\\begin\{matrix\}
a & b \\\\
c & d
\\end\{matrix\}
`}</Latex>
---
<Latex flow="column">{`
\\begin\{pmatrix\}
a & b \\\\
c & d
\\end\{pmatrix\}
`}</Latex>
---
<Latex flow="column">{`
\\begin\{bmatrix\}
a & b \\\\
c & d
\\end\{bmatrix\}
`}</Latex>
---
<Latex flow="column">{`
\\begin\{Bmatrix\}
a & b \\\\
c & d
\\end\{Bmatrix\}
`}</Latex>
---
<Latex flow="column">{`
\\begin\{vmatrix\}
a & b \\\\
c & d
\\end\{vmatrix\}
`}</Latex>
---
<Latex flow="column">{`
\\begin\{Vmatrix\}
a & b \\\\
c & d
\\end\{Vmatrix\}
`}</Latex>
---
<Latex flow="column">{`
\\begin\{smallmatrix\}
a & b \\\\
c & d
\\end\{smallmatrix\}
`}</Latex>
---
<Latex flow="column">{`
\\begin\{array\}\{cc\}
a & b \\\\
c & d
\\end\{array\}
`}</Latex>
## Changing the Shape of a Matrix
**To add or remove rows or columns** right click (or <kbd>CTRL</kbd>+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:
<Latex flow="column">{`
\\begin\{pmatrix\}
a & b \\\\[1.5em]
c & d
\\end\{pmatrix\}
`}</Latex>
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.
```json
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\}
}
import { Children, useEffect } from 'react';
export function onDisplayChange(e) { const useGlyphs = e.target.value === 'glyphs'; // We currently combine the display of glyphs with the "apple" class // We could have them separated... document.body.classList.toggle('apple', useGlyphs); document.body.classList.toggle('glyphs', useGlyphs); }
export function Keybinding({value, appleValue, children}) { const asKeylabel = (s, cls) => { const keybindings = s.split(/ /); return Children.map(keybindings, (keybinding => { const keys = keybinding.split('+'); let labels = keys.map(key => {key}); // Insert a "+" between each key labels = labels.reduce((acc, curr) => acc === null ? [curr] : [...acc, '+', curr], null); return
// Substitute a text label for the glyphs const noGlyphs = (s) => { return s.replace(/⌘|⌃|⇧|⌥|⤒|⤓|⇞|⇟|⇥|⌫|⌦|⏎|⌤|⇥/g, (glyph) => { const noGlyph = { '⌘': 'Ctrl', '⌃': 'Ctrl', '⇧': 'Shift', '⌥': 'Alt', '⤒': "Home", '⤓': 'End', "⇞": 'Page Up', '⇟': "Page Down", '⌫': 'Backspace', '⌦': 'Del', '⏎': 'Return', '⌤': 'Enter', '⇥': 'Tab' }[glyph]; return noGlyph ?? glyph; });
}
return
export function Shortcut({value, children}) { return
$$${value}$$
}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('apple', 'glyphs'), 16);
const glyphsRadio = document.getElementById('glyphs-radio');
const textRadio = document.getElementById('text-radio');
glyphsRadio.checked = isApple;
textRadio.checked = !isApple;
// Restore the body class when the page is reloaded
return () => document.body.classList.remove('apple', 'glyphs');
}, []); return <>{children}</>; }
<style>{` .keybinding-cell { display: flex; flex-flow: column; justify-content: start; gap: 4px; width: 20%; padding: 8px; margin: 0; background: transparent; border: 1px solid var(--callout-border-color); border-radius: 8px; box-sizing: content-box; font-family: var(--ui-font-family); font-weight: 400; text-align: center; } .keybinding-cell div:not(.keybinding-label) { align-items: center; justify-content: center; flex-wrap: wrap; color: var(--neutral-400); font-size: 1em; line-height: 2; } .keybinding-cell aside { margin-top: .5em; font-size: .8em; opacity: .8; } .keybinding-cell div kbd { display: flex; justify-content: center; align-items: center; font-family: var(--ui-font-family); font-size: .8em; line-height: 2; margin-left: 4px; margin-right: 4px; width: fit-content; min-width: 32px; min-height: 32px; height: 32px; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; border: var(--code-border); background: var(--neutral-900); border-radius: 4px; color: var(--blue-800); box-shadow: none; } .keybinding-label { display: flex; flex-flow: column; min-height: 4em; background: var(--callout-background); color: var(--text-color); align-items: center; justify-content: center; overflow-wrap: anywhere; background: var(--callout-background); color: var(--text-color); line-height: 1.1; padding: 8px; border-radius: 8px; margin-bottom: 4px; } .shortcut-cell { display: flex; flex-flow: column; align-items: center; justify-content: start; border-radius: 8px; border: 1px solid var(--callout-border-color); background: transparent; margin: .5em; padding: .5em; width: 20%; } .shortcut-cell div { text-align: center; } .shortcut-label { display: flex; flex-flow: column; min-height: 1em; width: 100%; background: var(--callout-background); color: var(--text-color); align-items: center; justify-content: center; overflow-wrap: anywhere; background: var(--callout-background); color: var(--text-color); line-height: 1; padding: 8px; border-radius: 8px; margin-bottom: 4px; } .shortcut-keys { font-family: var(--monospace-font-family); color: var(--primary-color); font-weight: 600; font-feature-settings: "calt" 0; } .shortcut-cell kbd { box-shadow: none; } {/* kbd { display: flex; justify-content: center; align-items: center; font-family: var(--ui-font-family); padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; font-size: 0.8em; border: var(--code-border); background: var(--neutral-900); border-radius: 4px; color: var(--blue-800); box-shadow: none; } */} @media (prefers-color-scheme: dark) { kbd { color: var(--blue-100); } } table td code { border: none; background: none; } table tr td:first-child { width: auto; } #special-keys { border-radius: 8px; margin-top: 2rem; border: var(--ui-border); padding: 1rem; } #special-keys-table { display: flex; flex-wrap: wrap; justify-content: space-around; gap: .25em; margin-bottom: 1em; } #special-keys-table > div { display: flex; flex-flow: column; align-items: center; width: 6em; font-size: 1rem; } #special-keys-table > div > kbd:first-child { display: flex; width: 74px; height: 64px; justify-content: center; align-items: center; font-size: 32px; font-weight: 500; color: var(--primary-color); } #special-keys-table > div > span, #special-keys-table > div > kbd:nth-child(2) { width: 100%; text-align: center; padding: 0; border: none; background: none; } #special-keys-table .label { font-size: 16px; } #special-keys-table .label kbd { padding: 0; border: none; box-shadow: none; background: none; font-weight: 600; } .keybindings-table { display: flex; flex-wrap: wrap; gap: 1em; } .inlineshortcut-table { display: flex; flex-wrap: wrap; } div[data-tooltip]:hover { position: relative; width: 100%; } div[data-tooltip]::after { display: none; position: absolute; content: attr(data-tooltip); min-width: calc(100% - 16px); height: calc(100% + 8px); padding: 8px 8px; top: -8px; left: 0; z-index: 2; justify-content: center; align-items: center; box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2); background: #616161; color: #fff; text-align: center; border-radius: 8px; font-family: var(--monospace-font-family); font-feature-settings: "calt" 0; /* Suppress ligatures */ font-weight: 400; font-size: 16px; } div[data-tooltip]:hover::after { display: flex; } .settings-row, .settings-stack { border-radius: 8px; border: var(--ui-border); padding: 1rem; display: flex; width: 100%; user-select: none; gap: 0; } .settings-row p , .settings-stack p { margin: 0; padding: 0; } .settings-row { align-items: center; justify-content: space-between; } .settings-stack { flex-flow: column; } .settings-stack .label { font-size: 1rem; font-weight: 700; margin-bottom: 0.5rem; } #special-keys { display: none; } body.apple #special-keys { display: block; } .if-apple, .keybinding-cell div.if-apple:not(.keybinding-label) { display: none; } body.apple .if-apple, body.apple .keybinding-cell div.if-apple:not(.keybinding-label) { display: inherit; } .if-glyphs, .if-not-glyphs { display: none; } body.glyphs .if-glyphs { display: inherit; } body:not(.glyphs) .if-not-glyphs { display: inherit; text-transform: uppercase; font-variant: small-caps; } `}</style>Commands to edit and modify a formula can be invoked by pressing some key combinations.
:::info[Note] The keybindings below are applicable to a US QWERTY keyboard. Some of the keybindings may not be available with other keyboard layouts. :::
Read more about definining your own **keybindings** and **shortcuts**.insert square bracket matrix insert braces matrix insert row insert column
Some sequence of characters are automatically translated to symbols. For example, typing P
followed by I
will result in "π".
Many of the ASCIIMath symbols are supported.
If the conversion was not desired, for example you actually meant "pi", type ctrl/⌘+Z to undo it.
!= >= <= << >>
* ** *** && xin in !in xx +- ÷ (-) (+) (/)
|__ __| |~ ~| || { } (: :)
The MathfieldElement
class is a DOM element that provides a math input
field.
It is a subclass of the standard
HTMLElement
class and as such inherits all of its properties and methods, such
as style
, tabIndex
, addEventListener()
, getAttribute()
, etc...
The MathfieldElement
class provides additional properties and methods to
control the display and behavior of <math-field>
elements.
To instantiate a MathfieldElement
use the <math-field>
tag in HTML.
You can also instantiate a MathfieldElement
programmatically using
new MathfieldElement()
.
// 1. Create a new MathfieldElement
const mf = new MathfieldElement();
// 2. Attach it to the DOM
document.body.appendChild(mf);
// 3. Modifying options after the mathfield has been attached to the DOM
mf.addEventListener("mount"), () => {
mf.smartFence = true;
});
Read more about customizing the appearance and behavior of the mathfield in the Customizing the Mathfield guide.
To customize the appearance of the mathfield, declare the following CSS variables (custom properties) in a ruleset that applies to the mathfield.
math-field {
--hue: 10 // Set the highlight color and caret to a reddish hue
}
Alternatively you can set these CSS variables programatically:
document.body.style.setProperty("--hue", "10");
Read more about the CSS variables available for customization.
You can customize the appearance and zindex of the virtual keyboard panel with some CSS variables associated with a selector that applies to the virtual keyboard panel container.
Read more about customizing the virtual keyboard appearance
In addition to the CSS variables, the mathfield exposes CSS parts that can be used to style the mathfield.
For example, to hide the menu button:
math-field::part(menu-toggle) {
display: none;
}
An attribute is a key-value pair set as part of the <math-field>
tag:
<math-field letter-shape-style="tex"></math-field>
The supported attributes are listed in the table below with their
corresponding property, which can be changed directly on the
MathfieldElement
object:
mf.value = "\\sin x";
mf.letterShapeStyle = "tex";
The values of attributes and properties are reflected, which means you can change one or the other, for example:
mf.setAttribute("letter-shape-style", "french");
console.log(mf.letterShapeStyle);
// Result: "french"
mf.letterShapeStyle ="tex";
console.log(mf.getAttribute("letter-shape-style");
// Result: "tex"
An exception is the value
property, which is not reflected on the value
attribute. For consistency with other DOM elements, the value
attribute
remains at its initial value.
Attribute | Property |
---|---|
disabled |
mf.disabled |
default-mode |
mf.defaultMode |
letter-shape-style |
mf.letterShapeStyle |
min-font-scale |
mf.minFontScale |
max-matrix-cols |
mf.maxMatrixCols |
popover-policy |
mf.popoverPolicy |
math-mode-space |
mf.mathModeSpace |
read-only |
mf.readOnly |
remove-extraneous-parentheses |
mf.removeExtraneousParentheses |
smart-fence |
mf.smartFence |
smart-mode |
mf.smartMode |
smart-superscript |
mf.smartSuperscript |
inline-shortcut-timeout |
mf.inlineShortcutTimeout |
script-depth |
mf.scriptDepth |
value |
value |
math-virtual-keyboard-policy |
mathVirtualKeyboardPolicy |
See more details about these attributes.
In addition, the following DOM elements global attributes are supported:
class
data-*
hidden
id
item*
style
tabindex
To listen to these events use mf.addEventListener()
. For events with
additional arguments, the arguments are available in event.detail
.
Event Name | Description |
---|---|
beforeinput |
The value of the mathfield is about to be modified. |
input |
The value of the mathfield has been modified. This happens on almost every keystroke in the mathfield. The evt.data property includes a copy of evt.inputType . See InputEvent |
change |
The user has committed the value of the mathfield. This happens when the user presses Return or leaves the mathfield. |
selection-change |
The selection (or caret position) in the mathfield has changed |
mode-change |
The mode (math , text ) of the mathfield has changed |
undo-state-change |
The state of the undo stack has changed. The evt.detail.type indicate if a snapshot was taken or an undo performed. |
read-aloud-status-change |
The status of a read aloud operation has changed |
before-virtual-keyboard-toggle |
The visibility of the virtual keyboard panel is about to change. The evt.detail.visible property indicate if the keyboard will be visible or not. Listen for this event on window.mathVirtualKeyboard |
virtual-keyboard-toggle |
The visibility of the virtual keyboard panel has changed. Listen for this event on window.mathVirtualKeyboard |
geometrychange |
The geometry of the virtual keyboard has changed. The evt.detail.boundingRect property is the new bounding rectangle of the virtual keyboard. Listen for this event on window.mathVirtualKeyboard |
blur |
The mathfield is losing focus |
focus |
The mathfield is gaining focus |
move-out |
The user has pressed an arrow key or the tab key, but there is nowhere to go. This is an opportunity to change the focus to another element if desired. `detail: {direction: 'forward' |
keypress |
The user pressed a physical keyboard key |
mount |
The element has been attached to the DOM |
unmount |
The element is about to be removed from the DOM |
HTMLElement
new MathfieldElement(options?): MathfieldElement
To create programmatically a new mathfield use:
let mfe = new MathfieldElement();
// Set initial value and options
mfe.value = "\\frac{\\sin(x)}{\\cos(x)}";
// Options can be set either as an attribute (for simple options)...
mfe.setAttribute("letter-shape-style", "french");
// ... or using properties
mfe.letterShapeStyle = "french";
// Attach the element to the DOM
document.body.appendChild(mfe);
Partial
<MathfieldOptions
>
Return an array of LaTeX syntax errors, if any.
get expression(): any
set expression(mathJson: any): void
If the Compute Engine library is available, return a boxed MathJSON expression representing the value of the mathfield.
To load the Compute Engine library, use:
import 'https://esm.run/@cortex-js/compute-engine';
get value(): string
set value(value: string): void
The content of the mathfield as a LaTeX expression.
document.querySelector('mf').value = '\\frac{1}{\\pi}'
getValue(format?): string
Return a textual representation of the content of the mathfield.
The format of the result. If using math-json
the Compute Engine library must be loaded, for example with:
import "https://esm.run/@cortex-js/compute-engine";
Default: "latex"
getValue(start, end, format?): string
Return the value of the mathfield from start
to end
number
number
getValue(range, format?): string
Return the value of the mathfield in range
insert(s, options?): boolean
Insert a block of text at the current insertion point.
This method can be called explicitly or invoked as a selector with
executeCommand("insert")
.
After the insertion, the selection will be set according to the
options.selectionMode
.
string
setValue(value?, options?): void
Set the content of the mathfield to the text interpreted as a LaTeX expression.
string
The last valid offset.
get position(): number
set position(offset: number): void
The position of the caret/insertion point, from 0 to lastOffset
.
get selection(): Readonly<Selection>
set selection(sel: number | Selection): void
An array of ranges representing the selection.
It is guaranteed there will be at least one element. If a discontinuous selection is present, the result will include more than one element.
getOffsetFromPoint(x, y, options?): number
The offset closest to the location (x, y)
in viewport coordinate.
bias
: if 0
, the vertical midline is considered to the left or
right sibling. If -1
, the left sibling is favored, if +1
, the right
sibling is favored.
number
number
-1
| 0
| 1
select(): void
Select the content of the mathfield.
static restoreFocusWhenDocumentFocused: boolean = true;
When switching from a tab to one that contains a mathfield that was previously focused, restore the focus to the mathfield.
This is behavior consistent with <textarea>
, however it can be
disabled if it is not desired.
Default: true
get backgroundColorMap(): (name) => string
set backgroundColorMap(value: (name) => string): void
get colorMap(): (name) => string
set colorMap(value: (name) => string): void
Map a color name as used in commands such as \textcolor{}{}
or
\colorbox{}{}
to a CSS color value.
Use this option to override the standard mapping of colors such as "yellow" or "red".
If the name is not one you expected, return undefined
and the default
color mapping will be applied.
If a backgroundColorMap()
function is not provided, the colorMap()
function will be used instead.
If colorMap()
is not provided, default color mappings are applied.
The following color names have been optimized for a legible foreground and background values, and are recommended:
red
,orange
,yellow
,lime
,green
,teal
,blue
,indigo
,purple
,magenta
,black
,dark-grey
,grey
,light-grey
,white
get defaultMode(): "text" | "math" | "inline-math"
set defaultMode(value: "text" | "math" | "inline-math"): void
The mode of the element when it is empty:
"math"
: equivalent to\displaystyle
(display math mode)"inline-math"
: equivalent to\inlinestyle
(inline math mode)"text"
: text mode
get environmentPopoverPolicy(): "auto" | "off" | "on"
set environmentPopoverPolicy(value: "auto" | "off" | "on"): void
If "auto"
a popover with commands to edit an environment (matrix)
is displayed when the virtual keyboard is displayed.
Default: "auto"
get letterShapeStyle(): "auto" | "tex" | "iso" | "french" | "upright"
set letterShapeStyle(value: "auto" | "tex" | "iso" | "french" | "upright"): void
Control the letter shape style:
letterShapeStyle |
xyz | ABC | αβɣ | ΓΔΘ |
---|---|---|---|---|
iso |
it | it | it | it |
tex |
it | it | it | up |
french |
it | up | up | up |
upright |
up | up | up | up |
(it) = italic (up) = upright
The default letter shape style is auto
, which indicates that french
should be used if the locale is "french", and tex
otherwise.
Historical Note
Where do the "french" rules come from? The TeX standard font, Computer Modern, is based on Monotype 155M, itself based on the Porson greek font which was one of the most widely used Greek fonts in english-speaking countries. This font had upright capitals, but slanted lowercase. In France, the traditional font for greek was Didot, which has both upright capitals and lowercase.
As for roman uppercase, they are recommended by "Lexique des règles typographiques en usage à l’Imprimerie Nationale". It should be noted that this convention is not universally followed.
get mathModeSpace(): string
set mathModeSpace(value: string): void
The LaTeX string to insert when the spacebar is pressed (on the physical or virtual keyboard).
Use "\;"
for a thick space, "\:"
for a medium space, "\,"
for a
thin space.
Do not use " "
(a regular space), as whitespace is skipped by LaTeX
so this will do nothing.
Default: ""
(empty string)
get maxMatrixCols(): number
set maxMatrixCols(value: number): void
Sets the maximum number of columns for the matrix environment. The default is
10 columns to match the behavior of the amsmath matrix environment.
Default: 10
get minFontScale(): number
set minFontScale(value: number): void
Set the minimum relative font size for nested superscripts and fractions. The value
should be a number between 0
and 1
. The size is in releative em
units relative to the
font size of the math-field
element. Specifying a value of 0
allows the math-field
to use its default sizing logic.
Default: 0
get placeholder(): string
set placeholder(value: string): void
A LaTeX string displayed inside the mathfield when there is no content.
get placeholderSymbol(): string
set placeholderSymbol(value: string): void
The symbol used to represent a placeholder in an expression.
Default: ▢
U+25A2 WHITE SQUARE WITH ROUNDED CORNERS
get popoverPolicy(): "auto" | "off"
set popoverPolicy(value: "auto" | "off"): void
If "auto"
a popover with suggestions may be displayed when a LaTeX
command is input.
Default: "auto"
get removeExtraneousParentheses(): boolean
set removeExtraneousParentheses(value: boolean): void
If true
, extra parentheses around a numerator or denominator are
removed automatically.
Default: true
get scriptDepth(): number | [number, number]
set scriptDepth(value: number | [number, number]): void
This option controls how many levels of subscript/superscript can be entered. For
example, if scriptDepth
is "1", there can be one level of superscript or
subscript. Attempting to enter a superscript while inside a superscript will
be rejected. Setting a value of 0 will prevent entry of any superscript or
subscript (but not limits for sum, integrals, etc...)
This can make it easier to enter equations that fit what's expected for the domain where the mathfield is used.
To control the depth of superscript and subscript independently, provide an
array: the first element indicate the maximum depth for subscript and the
second element the depth of superscript. Thus, a value of [0, 1]
would
suppress the entry of subscripts, and allow one level of superscripts.
get smartFence(): boolean
set smartFence(value: boolean): void
When true
and an open fence is entered via typedText()
it will
generate a contextually appropriate markup, for example using
\left...\right
if applicable.
When false
, the literal value of the character will be inserted instead.
get smartMode(): boolean
set smartMode(value: boolean): void
When true
, during text input the field will switch automatically between
'math' and 'text' mode depending on what is typed and the context of the
formula. If necessary, what was previously typed will be 'fixed' to
account for the new info.
For example, when typing "if x >0":
Type | Interpretation |
---|---|
i |
math mode, imaginary unit |
if |
text mode, english word "if" |
if x |
all in text mode, maybe the next word is xylophone? |
if x > |
"if" stays in text mode, but now "x >" is in math mode |
if x > 0 |
"if" in text mode, "x > 0" in math mode |
Default: false
Manually switching mode (by typing alt/option+=
) will temporarily turn
off smart mode.
Examples
slope = rise/run
If x > 0, then f(x) = sin(x)
x^2 + sin (x) when x > 0
When x<0, x^{2n+1}<0
Graph x^2 -x+3 =0 for 0<=x<=5
Divide by x-3 and then add x^2-1 to both sides
Given g(x) = 4x – 3, when does g(x)=0?
Let D be the set {(x,y)|0<=x<=1 and 0<=y<=x}
\int\_{the unit square} f(x,y) dx dy
For all n in NN
get smartSuperscript(): boolean
set smartSuperscript(value: boolean): void
When true
and a digit is entered in an empty superscript, the cursor
leaps automatically out of the superscript. This makes entry of common
polynomials easier and faster. If entering other characters (for example
"n+1") the navigation out of the superscript must be done manually (by
using the cursor keys or the spacebar to leap to the next insertion
point).
When false
, the navigation out of the superscript must always be done
manually.
get onInsertStyle(): InsertStyleHook
set onInsertStyle(value: InsertStyleHook): void
applyStyle(style, options?): void
Update the style (color, bold, italic, etc...) of the selection or sets the style to be applied to future input.
If there is no selection and no range is specified, the style will apply to the next character typed.
If a range is specified, the style is applied to the range, otherwise, if there is a selection, the style is applied to the selection.
If the operation is "toggle"
and the range already has this style,
remove it. If the range
has the style partially applied (i.e. only some sections), remove it from
those sections, and apply it to the entire range.
If the operation is "set"
, the style is applied to the range,
whether it already has the style or not.
The default operation is "set"
.
Readonly
<Style
>
Range
| {
operation
: "set"
| "toggle"
;
range
: Range
;
}
queryStyle(style): "some" | "all" | "none"
If there is a selection, return if all the atoms in the selection,
some of them or none of them match the style
argument.
If there is no selection, return 'all' if the current implicit style
(determined by a combination of the style of the previous atom and
the current style) matches the style
argument, 'none' if it does not.
Readonly
<Style
>
get macros(): Readonly<MacroDictionary>
set macros(value: MacroDictionary): void
A dictionary of LaTeX macros to be used to interpret and render the content.
For example, to add a new macro to the default macro dictionary:
mf.macros = {
...mf.macros,
smallfrac: '^{#1}\\!\\!/\\!_{#2}',
};
Note that ...mf.macros
is used to keep the existing macros and add to
them.
Otherwise, all the macros are replaced with the new definition.
The code above will support the following notation:
\smallfrac{5}{16}
get registers(): Registers
set registers(value: Registers): void
TeX registers represent "variables" and "constants".
Changing the values of some registers can modify the layout of math expressions.
The following registers might be of interest:
thinmuskip
: space between items of math listsmedmuskip
: space between binary operationsthickmuskip
: space between relational operatorsnulldelimiterspace
: minimum space to leave blank in delimiter constructions, for example around a fractiondelimitershortfall
: maximum space to overlap adjacent elements when a delimiter is too shortjot
: space between lines in an array, or between rows in a multiline constructarraycolsep
: space between columns in an arrayarraystretch
: factor by which to stretch the height of each row in an array
To modify a register, use:
mf.registers.arraystretch = 1.5;
mf.registers.thinmuskip = { dimension: 2, unit: "mu" };
mf.registers.medmuskip = "3mu";
static readAloudHook: (element, text) => void = defaultReadAloudHook;
static speakHook: (text) => void = defaultSpeakHook;
get static speechEngine(): "amazon" | "local"
set static speechEngine(value: "amazon" | "local"): void
Indicates which speech engine to use for speech output.
Use local
to use the OS-specific TTS engine.
Use amazon
for Amazon Text-to-Speech cloud API. You must include the
AWS API library and configure it with your API key before use.
See mathfield/guides/speech/ | Guide: Speech
get static speechEngineRate(): string
set static speechEngineRate(value: string): void
Sets the speed of the selected voice.
One of x-slow
, slow
, medium
, fast
, x-fast
or a value as a
percentage.
Range is 20%
to 200%
For example 200%
to indicate a speaking rate
twice the default rate.
get static speechEngineVoice(): string
set static speechEngineVoice(value: string): void
Indicates the voice to use with the speech engine.
This is dependent on the speech engine. For Amazon Polly, see here: https://docs.aws.amazon.com/polly/latest/dg/voicelist.html
get static textToSpeechMarkup(): "" | "ssml" | "ssml_step" | "mac"
set static textToSpeechMarkup(value: "" | "ssml" | "ssml_step" | "mac"): void
The markup syntax to use for the output of conversion to spoken text.
Possible values are ssml
for the SSML markup or mac
for the macOS
markup, i.e. [[ltr]]
.
get static textToSpeechRules(): "sre" | "mathlive"
set static textToSpeechRules(value: "sre" | "mathlive"): void
Specify which set of text to speech rules to use.
A value of mathlive
indicates that the simple rules built into MathLive
should be used.
A value of sre
indicates that the Speech Rule Engine from Volker Sorge
should be used.
(Caution) SRE is not included or loaded by MathLive. For this option to work SRE should be loaded separately.
See mathfield/guides/speech/ | Guide: Speech
get static textToSpeechRulesOptions(): Readonly<Record<string, string>>
set static textToSpeechRulesOptions(value: Record<string, string>): void
A set of key/value pairs that can be used to configure the speech rule engine.
Which options are available depends on the speech rule engine in use. There are no options available with MathLive's built-in engine. The options for the SRE engine are documented here
blur(): void
Remove the focus from the mathfield (will no longer respond to keyboard input).
focus(): void
Sets the focus to the mathfield (will respond to keyboard input).
hasFocus(): boolean
Return true if the mathfield is currently focused (responds to keyboard input).
getPromptRange(id): Range
Return the selection range for the specified prompt.
This can be used for example to select the content of the prompt.
mf.selection = mf.getPromptRange('my-prompt-id');
string
getPrompts(filter?): string[]
Return the id of the prompts matching the filter.
"undefined"
| "correct"
| "incorrect"
string
boolean
getPromptState(id): ["correct" | "incorrect", boolean]
string
getPromptValue(placeholderId, format?): string
Return the content of the \placeholder{}
command with the placeholderId
string
setPromptState(id, state, locked?): void
string
"undefined"
| "correct"
| "incorrect"
boolean
setPromptValue(id, content, insertOptions): void
string
string
Omit
<InsertOptions
, "insertionMode"
>
canRedo(): boolean
Return whether there are redoable items
canUndo(): boolean
Return whether there are undoable items
resetUndo(): void
Reset the undo stack
get inlineShortcuts(): Readonly<InlineShortcutDefinitions>
set inlineShortcuts(value: InlineShortcutDefinitions): void
The keys of this object literal indicate the sequence of characters that will trigger an inline shortcut.
get inlineShortcutTimeout(): number
set inlineShortcutTimeout(value: number): void
Maximum time, in milliseconds, between consecutive characters for them to be considered part of the same shortcut sequence.
A value of 0 is the same as infinity: any consecutive character will be candidate for an inline shortcut, regardless of the interval between this character and the previous one.
A value of 750 will indicate that the maximum interval between two characters to be considered part of the same inline shortcut sequence is 3/4 of a second.
This is useful to enter "+-" as a sequence of two characters, while also supporting the "±" shortcut with the same sequence.
The first result can be entered by pausing slightly between the first and second character if this option is set to a value of 250 or so.
Note that some operations, such as clicking to change the selection, or losing the focus on the mathfield, will automatically timeout the shortcuts.
get keybindings(): readonly Keybinding[]
set keybindings(value: readonly Keybinding[]): void
get menuItems(): readonly MenuItem[]
set menuItems(menuItems: readonly MenuItem[]): void
showMenu(_): boolean
{
x
: number
;
y
: number
;
}
number
number
KeyboardModifiers
static keypressVibration: boolean = true;
When a key on the virtual keyboard is pressed, produce a short haptic feedback, if the device supports it.
get mathVirtualKeyboardPolicy(): VirtualKeyboardPolicy
set mathVirtualKeyboardPolicy(value: VirtualKeyboardPolicy): void
get virtualKeyboardTargetOrigin(): string
set virtualKeyboardTargetOrigin(value: string): void
get static keypressSound(): Readonly<{
default: string;
delete: string;
return: string;
spacebar: string;
}>
set static keypressSound(value:
| string
| {
default: string;
delete: string;
return: string;
spacebar: string;
}): void
When a key on the virtual keyboard is pressed, produce a short audio feedback.
If the property is set to a string
, the same sound is played in all
cases. Otherwise, a distinct sound is played:
delete
a sound played when the delete key is pressedreturn
... when the return/tab key is pressedspacebar
... when the spacebar is presseddefault
... when any other key is pressed. This property is required, the others are optional. If they are missing, this sound is played as well.
The value of the properties should be either a string, the name of an
audio file in the soundsDirectory
directory or null
to suppress
the sound.
If the soundsDirectory
is null
, no sound will be played.
get static soundsDirectory(): string
set static soundsDirectory(value: string): void
A URL fragment pointing to the directory containing the optional sounds used to provide feedback while typing.
Some default sounds are available in the /dist/sounds
directory of the SDK.
Use null
to prevent any sound from being loaded.
get static decimalSeparator(): "," | "."
set static decimalSeparator(value: "," | "."): void
The symbol used to separate the integer part from the fractional part of a number.
When ","
is used, the corresponding LaTeX string is {,}
, in order
to ensure proper spacing (otherwise an extra gap is displayed after the
comma).
This affects:
- what happens when the
,
key is pressed (ifdecimalSeparator
is","
, the{,}
LaTeX string is inserted when following some digits) - the label and behavior of the "." key in the default virtual keyboard
Default: "."
get static fractionNavigationOrder(): "denominator-numerator" | "numerator-denominator"
set static fractionNavigationOrder(s: "denominator-numerator" | "numerator-denominator"): void
When using the keyboard to navigate a fraction, the order in which the numerator and navigator are traversed:
"numerator-denominator"
: first the elements in the numerator, then the elements in the denominator."denominator-numerator"
: first the elements in the denominator, then the elements in the numerator. In some East-Asian cultures, fractions are read and written denominator first ("fēnzhī"). With this option the keyboard navigation follows this convention.
Default: "numerator-denominator"
get static locale(): string
set static locale(value: string): void
The locale (language + region) to use for string localization.
If none is provided, the locale of the browser is used.
get static strings(): Readonly<Record<string, Record<string, string>>>
set static strings(value: Record<string, Record<string, string>>): void
An object whose keys are a locale string, and whose values are an object of string identifier to localized string.
Example
mf.strings = {
"fr-CA": {
"tooltip.undo": "Annuler",
"tooltip.redo": "Refaire",
}
}
If the locale is already supported, this will override the existing strings. If the locale is not supported, it will be added.
static createHTML: (html) => any;
Support for Trusted Type.
This optional function will be called before a string of HTML is injected in the DOM, allowing that string to be sanitized according to a policy defined by the host.
Consider using this option if you are displaying untrusted content. Read more about Security Considerations
static version: string = '0.105.2';
get disabled(): boolean
set disabled(value: boolean): void
get mode(): ParseMode
set mode(value: ParseMode): void
get readonly(): boolean
set readonly(value: boolean): void
get readOnly(): boolean
set readOnly(value: boolean): void
get static computeEngine(): ComputeEngine
set static computeEngine(value: ComputeEngine): void
A custom compute engine instance. If none is provided, a default one is
used. If null
is specified, no compute engine is used.
get static fontsDirectory(): string
set static fontsDirectory(value: string): void
A URL fragment pointing to the directory containing the fonts necessary to render a formula.
These fonts are available in the /fonts
directory of the npm package.
Customize this value to reflect where you have copied these fonts, or to use the CDN version.
The default value is "./fonts"
. Use null
to prevent
any fonts from being loaded.
Changing this setting after the mathfield has been created will have no effect.
{
// Use the CDN version
fontsDirectory: ''
}
{
// Use a directory called "fonts", located next to the
// `mathlive.js` (or `mathlive.mjs`) file.
fontsDirectory: './fonts'
}
{
// Use a directory located at the root of your website
fontsDirectory: 'https://example.com/fonts'
}
get static isFunction(): (command) => boolean
set static isFunction(value: (command) => boolean): void
get static plonkSound(): string
set static plonkSound(value: string): void
Sound played to provide feedback when a command has no effect, for example when pressing the spacebar at the root level.
The property is either:
- a string, the name of an audio file in the
soundsDirectory
directory null
to turn off the sound
If the soundsDirectory
is null
, no sound will be played.
getElementInfo(offset): ElementInfo
number
static loadSound(sound): Promise<void>
"keypress"
| "plonk"
| "delete"
| "spacebar"
| "return"
static openUrl(href): void
string
static playSound(name): Promise<void>
"keypress"
| "plonk"
| "delete"
| "spacebar"
| "return"
executeCommand(selector): boolean
Execute a command
defined by a selector.
mfe.executeCommand('add-column-after');
mfe.executeCommand(['switch-mode', 'math']);
A selector, or an array whose first element is a selector, and whose subsequent elements are arguments to the selector.
Selectors can be passed either in camelCase or kebab-case.
// Both calls do the same thing
mfe.executeCommand('selectAll');
mfe.executeCommand('select-all');
executeCommand(selector, ...args): boolean
Execute a command
defined by a selector.
mfe.executeCommand('add-column-after');
mfe.executeCommand(['switch-mode', 'math']);
A selector, or an array whose first element is a selector, and whose subsequent elements are arguments to the selector.
Selectors can be passed either in camelCase or kebab-case.
// Both calls do the same thing
mfe.executeCommand('selectAll');
mfe.executeCommand('select-all');
...unknown
[]
executeCommand(selector): boolean
Execute a command
defined by a selector.
mfe.executeCommand('add-column-after');
mfe.executeCommand(['switch-mode', 'math']);
[Selector
, ...unknown[]
]
A selector, or an array whose first element is a selector, and whose subsequent elements are arguments to the selector.
Selectors can be passed either in camelCase or kebab-case.
// Both calls do the same thing
mfe.executeCommand('selectAll');
mfe.executeCommand('select-all');
get onExport(): (from, latex, range) => string
set onExport(value: (from, latex, range) => string): void
This hook is invoked when the user has requested to export the content of the mathfield, for example when pressing ctrl/command+C.
This hook should return as a string what should be exported.
The range
argument indicates which portion of the mathfield should be
exported. It is not always equal to the current selection, but it can
be used to export a format other than LaTeX.
By default this is:
return `\\begin{equation*}${latex}\\end{equation*}`;
get onInlineShortcut(): (sender, symbol) => string
set onInlineShortcut(value: (sender, symbol) => string): void
A hook invoked when a string of characters that could be interpreted as shortcut has been typed.
If not a special shortcut, return the empty string ""
.
Use this handler to detect multi character symbols, and return them wrapped appropriately,
for example \mathrm{${symbol}}
.
get onScrollIntoView(): (sender) => void
set onScrollIntoView(value: (sender) => void): void
A hook invoked when scrolling the mathfield into view is necessary.
Use when scrolling the page would not solve the problem, e.g. when the mathfield is in another div that has scrollable content.
These attributes of the <math-field>
element correspond to matching properties.
[key: string]: unknown
default-mode: string;
inline-shortcut-timeout: string;
Maximum time, in milliseconds, between consecutive characters for them to be considered part of the same shortcut sequence.
A value of 0 is the same as infinity: any consecutive character will be candidate for an inline shortcut, regardless of the interval between this character and the previous one.
A value of 750 will indicate that the maximum interval between two characters to be considered part of the same inline shortcut sequence is 3/4 of a second.
This is useful to enter "+-" as a sequence of two characters, while also supporting the "±" shortcut with the same sequence.
The first result can be entered by pausing slightly between the first and second character if this option is set to a value of 250 or so.
Note that some operations, such as clicking to change the selection, or losing the focus on the mathfield, will automatically timeout the shortcuts.
letter-shape-style: string;
math-mode-space: string;
The LaTeX string to insert when the spacebar is pressed (on the physical or
virtual keyboard). Empty by default. Use \;
for a thick space, \:
for
a medium space, \,
for a thin space.
math-virtual-keyboard-policy: VirtualKeyboardPolicy;
"auto"
: the virtual keyboard is triggered when a mathfield is focused on a touch capable device."manual"
: the virtual keyboard is not triggered automatically"sandboxed"
: the virtual keyboard is displayed in the current browsing context (iframe) if it has a defined container or is the top-level browsing context.
max-matrix-cols: number;
min-font-scale: number;
placeholder: string;
When the mathfield is empty, display this placeholder LaTeX string instead
popover-policy: string;
read-only: boolean;
When true, the user cannot edit the mathfield.
remove-extraneous-parentheses: boolean;
script-depth: string;
smart-fence: string;
When on
and an open fence is entered via typedText()
it will
generate a contextually appropriate markup, for example using
\left...\right
if applicable.
When off
, the literal value of the character will be inserted instead.
smart-mode: string;
When on
, during text input the field will switch automatically between
'math' and 'text' mode depending on what is typed and the context of the
formula. If necessary, what was previously typed will be 'fixed' to
account for the new info.
For example, when typing "if x >0":
Type | Interpretation |
---|---|
"i" | math mode, imaginary unit |
"if" | text mode, english word "if" |
"if x" | all in text mode, maybe the next word is xylophone? |
"if x >" | "if" stays in text mode, but now "x >" is in math mode |
"if x > 0" | "if" in text mode, "x > 0" in math mode |
Smart Mode is off
by default.
Manually switching mode (by typing alt/option+=
) will temporarily turn
off smart mode.
Examples
- slope = rise/run
- If x > 0, then f(x) = sin(x)
- x^2 + sin (x) when x > 0
- When x<0, x^b;2n+1d;<0
- Graph x^2 -x+3 =0 for 0<=x<=5
- Divide by x-3 and then add x^2-1 to both sides
- Given g(x) = 4x – 3, when does g(x)=0?
- Let D be the set b;(x,y)|0<=x<=1 and 0<=y<=xd;
- \int_b;the unit squared; f(x,y) dx dy
- For all n in NN
smart-superscript: string;
When on
, when a digit is entered in an empty superscript, the cursor
leaps automatically out of the superscript. This makes entry of common
polynomials easier and faster. If entering other characters (for example
"n+1") the navigation out of the superscript must be done manually (by
using the cursor keys or the spacebar to leap to the next insertion
point).
When off
, the navigation out of the superscript must always be done
manually.
virtual-keyboard-target-origin: string;
Specify the targetOrigin
parameter for
postMessage
to send control messages from child to parent frame to remote control
of mathfield component.
Default: window.origin
Some additional information about an element of the formula
returned by mf.getElementInfo()
.
optional bounds: DOMRect;
The bounding box of the element
optional data: Record<string, string | undefined>;
HTML attributes associated with element or its ancestores, set with
\htmlData
optional depth: number;
The depth in the expression tree. 0 for top-level elements
optional id: string;
id associated with this element or its ancestor, set with \htmlId
or
\cssId
optional latex: string;
A LaTeX representation of the element
optional mode: ParseMode;
The mode (math, text or LaTeX)
optional style: Style;
The style (color, weight, variant, etc...) of this element.
optional feedback: boolean;
If true
, provide audio and haptic feedback
optional focus: boolean;
If true
, the mathfield will be focused after the insertion
optional format: OutputFormat | "auto";
The format of the input string:
"auto" |
The string is a LaTeX fragment or command (default) |
"latex" |
The string is a LaTeX fragment |
optional insertionMode: "replaceSelection" | "replaceAll" | "insertBefore" | "insertAfter";
optional mode: ParseMode | "auto";
If "auto"
or omitted, the current mode is used
optional scrollIntoView: boolean;
If true
, scroll the mathfield into view after insertion such that the insertion point is visible
optional selectionMode: "placeholder" | "after" | "before" | "item";
Describes where the selection will be after the insertion:
"placeholder" |
The selection will be the first available placeholder in the text that has been inserted (default) |
"after" |
The selection will be an insertion point after the inserted text |
"before" |
The selection will be an insertion point before the inserted text |
"item" |
The inserted text will be selected |
optional silenceNotifications: boolean;
If true
, silence notifications during insertion
optional style: Style;
The style applied to the inserted content
Event re-targeting
Some events bubble up through the DOM tree, so that they are detectable by any element on the page.
Bubbling events fired from within shadow DOM are re-targeted so that, to any listener external to your component, they appear to come from your component itself.
Custom Event Bubbling
By default, a bubbling custom event fired inside shadow DOM will stop bubbling when it reaches the shadow root.
To make a custom event pass through shadow DOM boundaries, you must set
both the composed
and bubbles
flags to true.
The move-out
event signals that the user pressed an arrow key or
tab key but there was no navigation possible inside the mathfield.
This event provides an opportunity to handle this situation, for example by focusing an element adjacent to the mathfield.
If the event is canceled (i.e. evt.preventDefault()
is called inside your
event handler), the default behavior is to play a "plonk" sound.
direction: "forward" | "backward" | "upward" | "downward";
type OutputFormat =
| "ascii-math"
| "latex"
| "latex-expanded"
| "latex-unstyled"
| "latex-without-placeholders"
| "math-json"
| "math-ml"
| "plain-text"
| "spoken"
| "spoken-text"
| "spoken-ssml"
| "spoken-ssml-with-highlighting";
Format | Description |
---|---|
"ascii-math" |
A string of ASCIIMath. |
"latex" |
LaTeX rendering of the content, with LaTeX macros not expanded. |
"latex-expanded" |
All macros are recursively expanded to their definition. |
"latex-unstyled" |
Styling (background color, color) is ignored |
"latex-without-placeholders" |
Replace \placeholder commands with their body |
"math-json" |
A MathJSON abstract syntax tree, as an object literal formated as a JSON string. Note: you must import the CortexJS Compute Engine to obtain a result. |
"math-ml" |
A string of MathML markup. |
"plain-text" |
A plain text rendering of the content. |
"spoken" |
Spoken text rendering, using the default format defined in config, which could be either text or SSML markup. |
"spoken-text" |
A plain spoken text rendering of the content. |
"spoken-ssml" |
A SSML (Speech Synthesis Markup Language) version of the content, which can be used with some text-to-speech engines such as AWS. |
"spoken-ssml-with-highlighting" |
Like "spoken-ssml" but with additional annotations necessary for synchronized highlighting (read aloud). |
To use the"math-json"
format the Compute Engine library must be loaded. Use for example:
import "https://esm.run/@cortex-js/compute-engine";
type Offset = number;
Position of the caret/insertion point from the beginning of the formula.
The first position is 0. The last valid offset is mf.lastOffset
.
See Also
type Range = [Offset, Offset];
A pair of offsets (boundary points) that denote a fragment of a formula.
A range is said to be collapsed when start
and end
are equal.
When specifying a range, a negative offset can be used to indicate an
offset relative to the last valid offset, i.e. -1
is the last valid
offset, -2
is one offset before that, etc...
A normalized range will always be such that start <= end, start >= 0, end >= 0, start < lastOffset, end < lastOffset. All the methods return a normalized range.
See Also
A selection is a set of ranges (to support discontinuous selection, for example when selecting a column in a matrix).
If there is a single range and that range is collapsed, the selection is collapsed.
A selection can also have a direction. While many operations are
insensitive to the direction, a few are. For example, when selecting a
fragment of a formula from left to right, the direction of this range will
be "forward"
.
Pressing the left arrow key will sets the insertion at the start of the range.
Conversely, if the selection is made from right to left, the direction is
"backward"
and pressing the left arrow key will set the insertion point at
the end of the range.
See Also
optional direction: "forward" | "backward" | "none";
ranges: Range[];
optional backgroundColor: string;
optional color: string;
optional fontFamily: FontFamily;
optional fontSeries: FontSeries;
optional fontShape: FontShape;
optional fontSize: "auto" | FontSize;
optional variant: Variant;
optional variantStyle: VariantStyle;
optional operation: "set" | "toggle";
optional range: Range;
optional silenceNotifications: boolean;
type FontFamily = "none" | "roman" | "monospace" | "sans-serif";
type FontSeries = "auto" | "m" | "b" | "l" | "";
type FontShape = "auto" | "n" | "it" | "sl" | "sc" | "";
type FontSize = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
type InsertStyleHook = (sender, at, info) => Readonly<Style>;
type MathstyleName = "displaystyle" | "textstyle" | "scriptstyle" | "scriptscriptstyle";
type Variant =
| "ams"
| "double-struck"
| "calligraphic"
| "script"
| "fraktur"
| "sans-serif"
| "monospace"
| "normal"
| "main"
| "math";
Variants indicate a stylistic alternate for some characters.
Typically, those are controlled with explicit commands, such as
\mathbb{}
or \mathfrak{}
. This type is used with the
MathfieldElement.applyStyle
method to change the styling of a range of
selected characters.
In mathematical notation these variants are used not only for visual presentation, but they may have semantic significance.
For example,
- the set ℂ should not be confused with
- the physical unit 𝖢 (Coulomb).
When rendered, these variants can map to some built-in fonts.
LaTeX supports a limited set of characters. However, MathLive will map characters not supported by LaTeX fonts (double-stuck variant for digits for example) to a Unicode character (see Mathematical Alphanumeric Symbols on Wikipedia ).
normal
is a synthetic variant that maps either to main
(upright) or
math
(italic) depending on the symbol and the letterShapeStyle
.
The math
variant has italic characters as well as slightly different
letter shape and spacing (a bit more space after the "f" for example), so
it's not equivalent to a main
variant with italic
variant style applied.
See Also
type VariantStyle = "up" | "bold" | "italic" | "bolditalic" | "";
Some variants support stylistic variations.
Note that these stylistic variations support a limited set of characters, typically just uppercase and lowercase letters, and digits 0-9 in some cases.
variant | up |
bold |
italic |
bolditalic |
---|---|---|---|---|
normal |
ABCabc012 | 𝐀𝐁𝐂𝐚𝐛𝐜𝟎𝟏𝟐 | 𝐴𝐵𝐶𝑎𝑏𝑐 | 𝑨𝑩𝑪𝒂𝒃𝒄 |
double-struck |
𝔸𝔹ℂ𝕒𝕓𝕔𝟘𝟙𝟚 | n/a | n/a | n/a |
calligraphic |
𝒜ℬ𝒞𝒶𝒷𝒸 | 𝓐𝓑𝓒𝓪𝓫𝓬 | n/a | n/a |
fraktur |
𝔄𝔅ℭ𝔞𝔟𝔠 | 𝕬𝕭𝕮𝖆𝖇𝖈 | n/a | n/a |
sans-serif |
𝖠𝖡𝖢𝖺𝖻𝖼𝟢𝟣𝟤 | 𝗔𝗕𝗖𝗮𝗯𝗰𝟬𝟭𝟮 | 𝘈𝘉𝘊𝘢𝘣𝘤 | 𝘼𝘽𝘾𝙖𝙗𝙘 |
monospace |
𝙰𝙱𝙲𝚊𝚋𝚌 | n/a | n/a | n/a |
See Also
optional args: number;
Number of arguments (#1
, etc...) in the macro definition
optional captureSelection: boolean;
If false
elements inside the macro can be selected
def: string;
Definition of the macro as a LaTeX expression
optional expand: boolean;
If false
, even if expandMacro
is true, do not expand.
type MacroDictionary = Record<string,
| string
| Partial<MacroDefinition>
| MacroPackageDefinition>;
A dictionary of LaTeX macros to be used to interpret and render the content.
For example:
mf.macros = { smallfrac: "^{#1}\\!\\!/\\!_{#2}" };
The code above will support the following notation:
\smallfrac{5}{16}
See Also
optional captureSelection: boolean;
package: Record<string, string | MacroDefinition>;
optional primitive: boolean;
type NormalizedMacroDictionary = Record<string, MacroDefinition>;
A dimension is used to specify the size of things
dimension: number;
optional unit: DimensionUnit;
type DimensionUnit =
| "pt"
| "mm"
| "cm"
| "ex"
| "px"
| "em"
| "bp"
| "dd"
| "pc"
| "in"
| "mu"
| "fil"
| "fill"
| "filll";
Glue represents flexible spacing, that is a dimension that
can grow (by the grow
property) or shrink (by the shrink
property).
glue: Dimension;
optional grow: Dimension;
optional shrink: Dimension;
type LatexValue = {
relax: boolean;
} &
| Dimension
| Glue
| {
string: string;
}
| {
base: "decimal" | "octal" | "hexadecimal" | "alpha";
number: number;
}
| {
factor: number;
global: boolean;
register: string;
};
A LaTeX expression represent a sequence of tokens that can be evaluated to a value, such as a dimension.
type Registers = Record<string, number | string | LatexValue>;
TeX registers represent "variables" and "constants".
Changing the values of some registers can modify the layout of math expressions.
The following registers might be of interest:
thinmuskip
: space between items of math listsmedmuskip
: space between binary operationsthickmuskip
: space between relational operatorsnulldelimiterspace
: minimum space to leave blank in delimiter constructions, for example around a fractiondelimitershortfall
: maximum space to overlap adjacent elements when a delimiter is too shortjot
: space between lines in an array, or between rows in a multiline constructarraycolsep
: space between columns in an arrayarraystretch
: factor by which to stretch the height of each row in an array
To modify a register, use:
mf.registers.arraystretch = 1.5;
mf.registers.thinmuskip = { dimension: 2, unit: "mu" };
mf.registers.medmuskip = "3mu";
To perform editing commands on a mathfield, use MathfieldElement.executeCommand
with the commands below.
const mf = document.getElementById('mathfield');
mf.executeCommand('selectAll');
mf.executeCommand('copyToClipboard');
Some commands require an argument, for example to insert a character:
mf.executeCommand('insert("x")' });
The argument can be specified in parentheses after the command name, or using an array:
mf.executeCommand(['switchMode', 'latex']);
// Same as mf.executeCommand('switchMode("latex")');
Commands (and executeCommand()
) return true if they resulted in a dirty
state.
extendSelectionBackward: (model) => boolean;
extendSelectionDownward: (model) => boolean;
extendSelectionForward: (model) => boolean;
extendSelectionUpward: (model) => boolean;
extendToGroupEnd: (model) => boolean;
extendToGroupStart: (model) => boolean;
extendToMathFieldEnd: (model) => boolean;
extendToMathFieldStart: (model) => boolean;
extendToNextBoundary: (model) => boolean;
extendToNextWord: (model) => boolean;
extendToPreviousBoundary: (model) => boolean;
extendToPreviousWord: (model) => boolean;
moveAfterParent: (model) => boolean;
moveBeforeParent: (model) => boolean;
moveDown: (model) => boolean;
moveToGroupEnd: (model) => boolean;
moveToGroupStart: (model) => boolean;
moveToMathfieldEnd: (model) => boolean;
moveToMathfieldStart: (model) => boolean;
moveToNextChar: (model) => boolean;
moveToNextGroup: (model) => boolean;
moveToNextPlaceholder: (model) => boolean;
moveToNextWord: (model) => boolean;
moveToOpposite: (model) => boolean;
moveToPreviousChar: (model) => boolean;
moveToPreviousGroup: (model) => boolean;
moveToPreviousPlaceholder: (model) => boolean;
moveToPreviousWord: (model) => boolean;
moveToSubscript: (model) => boolean;
moveToSuperscript: (model) => boolean;
moveUp: (model) => boolean;
selectAll: (model) => boolean;
selectGroup: (model) => boolean;
applyStyle: (mathfield, style) => boolean;
commit: (mathfield) => boolean;
dispatchEvent: (mathfield, name, detail) => boolean;
Dispatch a custom event on the host (mathfield)
hideVirtualKeyboard: (mathfield) => boolean;
insert: (mathfield, s, options) => boolean;
insertDecimalSeparator: (mathfield) => boolean;
performWithFeedback: (mathfield, command) => boolean;
Perform a command and include interactive feedback such as sound and haptic feedback.
This is useful to simulate user interaction, for example for commands from the virtual keyboard
plonk: (mathfield) => boolean;
showVirtualKeyboard: (mathfield) => boolean;
speak: (mathfield, scope, options) => boolean;
Mathfield
How much of the formula should be spoken:
all |
the entire formula |
selection |
the selection portion of the formula |
left |
the element to the left of the selection |
right |
the element to the right of the selection |
group |
the group (numerator, root, etc..) the selection is in |
parent |
the parent of the selection |
boolean
In addition to speaking the requested portion of the formula, visually highlight it as it is read (read aloud functionality)
switchMode: (mathfield, mode) => boolean;
toggleContextMenu: (mathfield) => boolean;
toggleKeystrokeCaption: (mathfield) => boolean;
toggleVirtualKeyboard: (mathfield) => boolean;
typedText: (text, options) => boolean;
addColumnAfter: (model) => boolean;
addColumnBefore: (model) => boolean;
addRowAfter: (model) => boolean;
addRowBefore: (model) => boolean;
removeColumn: (model) => boolean;
removeRow: (model) => boolean;
setEnvironment: (model, environment) => boolean;
complete: (mathfield) => boolean;
nextSuggestion: (mathfield) => boolean;
previousSuggestion: (mathfield) => boolean;
copyToClipboard: (mathfield) => boolean;
cutToClipboard: (mathfield) => boolean;
pasteFromClipboard: (mathfield) => boolean;
deleteAll: (model) => boolean;
deleteBackward: (model) => boolean;
deleteForward: (model) => boolean;
deleteNextWord: (model) => boolean;
deletePreviousWord: (model) => boolean;
deleteToGroupEnd: (model) => boolean;
deleteToGroupStart: (model) => boolean;
deleteToMathFieldEnd: (model) => boolean;
deleteToMathFieldStart: (model) => boolean;
insertPrompt: (mathfield, id?, options?) => boolean;
scrollIntoView: (mathfield) => boolean;
scrollToEnd: (mathfield) => boolean;
scrollToStart: (mathfield) => boolean;
redo: (mathfield) => boolean;
undo: (mathfield) => boolean;
hideVirtualKeyboard: () => boolean;
showVirtualKeyboard: () => boolean;
switchKeyboardLayer: (mathfield, layer) => boolean;
toggleVirtualKeyboard: () => boolean;
type Selector = Keys<Commands>;
type SpeechScope = "all" | "selection" | "left" | "right" | "group" | "parent";
How much of the formula should be spoken:
all |
the entire formula |
selection |
the selection portion of the formula |
left |
the element to the left of the selection |
right |
the element to the right of the selection |
group |
the group (numerator, root, etc..) the selection is in |
parent |
the parent of the selection |
type InlineShortcutDefinition =
| string
| {
after: string;
value: string;
};
An inline shortcut can be specified as a simple string or as an object literal with additional options:
config.inlineShortcuts = {
half: '\\frac{1}{2}',
in: {
after: 'space+letter+digit+symbol+fence',
value: '\\in',
},
};
When using a string, the shortcut applies regardless of the characters surrounding it.
When using an object literal the value
key is required an indicate the
shortcut substitution.
The "after"
key, if present, indicate in what context (preceding characters)
the shortcut will apply. One or more values can be specified, separated by a '|'
character. If any of the values match, the shortcut is applicable.
Possible values are:
"space" |
A spacing command, such as \quad |
"nothing" |
The begining of a group |
"surd" |
A square root or n-th root |
"frac" |
A fraction |
"function" |
A function such as \sin or f |
"letter" |
A letter, such as x or n |
"digit" |
0 through 9 |
"binop" |
A binary operator, such as + |
"relop" |
A relational operator, such as = |
"punct" |
A punctuation mark, such as , |
"array" |
An array, such as a matrix or cases statement |
"openfence" |
An opening fence, such as ( |
"closefence" |
A closing fence such as } |
"text" |
Some plain text |
type InlineShortcutDefinitions = Record<string, InlineShortcutDefinition>;
A keybinding associates a combination of physical keyboard keys with a command.
For example:
{
"key": "cmd+a",
"command": "selectAll",
},
{
"key": 'ctrl+[Digit2]',
"ifMode": 'math',
"command": ['insert', '\\sqrt{#0}'],
}
command:
| Selector
| string[]
| [string, any]
| [string, any, any]
| [string, any, any, any];
The command is a single selector, or a selector with arguments
optional ifLayout: string[];
optional ifMode: ParseMode;
If specified, this indicates in which mode this keybinding will apply. If none is specified, the keybinding will apply in every mode.
optional ifPlatform:
| "macos"
| "!macos"
| "windows"
| "!windows"
| "linux"
| "!linux"
| "ios"
| "!ios"
| "android"
| "!android"
| "chromeos"
| "!chromeos";
If specified, this indicates the OS platform to which this keybinding apply.
For example, if set to !macos
this key binding will apply to every
platform, except macOS.
key: string;
The pressed keys that will trigger this keybinding.
The key
is made up of modifiers and the key itself.
The following modifiers can be used:
Platform | Modifiers |
---|---|
macOS, iOS | ctrl , shift , alt , cmd |
Windows | ctrl , shift , alt , win |
Linux, Android, ChromeOS | ctrl , shift , alt , meta |
If the cmd
modifier is used, the keybinding will only apply on macOS.
If the win
modifier is used, the keybinding will only apply to Windows.
If the meta
modifier is used, the keybinding will apply to platforms
other than macOS or Windows.
The alt
key is the option
key on Apple keyboards.
The following values for keys can be used:
a
–z
,0
–9
`
,-
,=
,[
,]
,\
,;
,'
,,
,.
,/
left
,up
,right
,down
,pageup
,pagedown
,end
,home
tab
,enter
,escape
,space
,backspace
,delete
f1
–f19
pausebreak
,capslock
,insert
numpad0
–numpad9
,numpad_multiply
,numpad_add
,numpad_separator
numpad_subtract
,numpad_decimal
,numpad_divide
The values will be remapped based on the current keyboard layout. So, for
example if a
is used, on a French AZERTY keyboard the keybinding will be
associated with the key labeled 'A' (event though it corresponds to the
key labeled 'Q' on a US QWERTY keyboard).
To associate keybindings with physical keys independent of the keyboard layout, use the following keycodes:
[KeyA]
–[KeyZ]
,[Digit0]
–[Digit9]
[Backquote]
,[Minus]
,[Equal]
,[BracketLeft]
,[BracketRight]
,[Backslash]
,[Semicolon]
,[Quote]
,[Comma]
,[Period]
,[Slash]
[ArrowLeft]
,[ArrowUp]
,[ArrowRight]
,[ArrowDown]
,[PageUp]
,[PageDown]
,[End]
,[Home]
[Tab]
,[Enter]
,[Escape]
,[Space]
,[Backspace]
,[Delete]
[F1]
–[F19]
[Pause]
,[CapsLock]
,[Insert]
[Numpad0]
–[Numpad9]
,[NumpadMultiply]
,[NumpadAdd]
,[NumpadComma]
[NumpadSubtract]
,[NumpadDecimal]
,[NumpadDivide]
For example, using [KeyQ]
will map to the the key labeled 'Q' on a QWERTY
keyboard, and to the key labeled 'A' on an AZERTY keyboard.
As a general guideline, it is preferable to use the key values a
–z
for keybinding that are pseudo-mnemotechnic. For the other, it is generally
preferable to use the keycodes.
Consider the key combination: alt+2
. With an AZERTY (French) layout,
the digits (i.e. '2') are only accessible when shifted. The '2' key produces
'é' when not shifted. It is therefore impossible on an AZERTY keyboard to
produce the alt+2
key combination, at best it would be alt+shift+2
.
To indicate that the intended key combination should be alt
and the
key on the keyboard which has the position of the 2
key on a US keyboard,
a key code should be used instead: alt+[Digit2]
. This will correspond
to a key combination that can be generated on any keyboard.
type DynamicValue<T> = T | (modifiers) => T;
• T
type MenuItem<T> =
| MenuItemDivider
| MenuItemHeading
| MenuItemSubmenu
| MenuItemCommand<T>;
Declaration of a menu item
• T = unknown
optional ariaLabel: DynamicValue<string>;
An accessible text string that describes the item.
Usually not necessary, as the label
is used for this,
however if the menu item is for example a color swatch,
the ariaLabel
can be used to describe the color.
optional checked: DynamicValue<boolean | "mixed">;
optional class: DynamicValue<string>;
A CSS class applied to the item
optional data: T;
This data payload is passed to the onMenuSelect()
hook and with the menu-select
event
optional enabled: DynamicValue<boolean>;
optional id: string;
This id string is passed to the onMenuSelect()
hook and with the menu-select
event
optional keyboardShortcut: string;
optional label: DynamicValue<string>;
A string of HTML markup used to describe the item
optional onMenuSelect: (_) => void;
When this menu item is selected, a menu-select
event is dispatched
and this hook is called.
optional tooltip: DynamicValue<string>;
optional type: "command";
optional visible: DynamicValue<boolean>;
A divider is a visual separator between menu items. It is not selectable.
type: "divider";
A heading is a menu item that is not selectable and used to group menu items.
If following items (until next divider or heading) are not visible, the heading is not visible either.
optional ariaLabel: DynamicValue<string>;
optional class: DynamicValue<string>;
optional label: DynamicValue<string>;
optional tooltip: DynamicValue<string>;
type: "heading";
These props are passed to the menu-select
event and onMenuSelect
hook
id
: theid
associated with the menu item.data
: thedata
payload associated with the menu itemmodifiers
: the keyboard modifiers that were pressed when the menu item was selected
optional data: T;
optional id: string;
optional modifiers: KeyboardModifiers;
optional ariaLabel: DynamicValue<string>;
optional class: DynamicValue<string>;
optional columnCount: number;
If the menu is arranged in a custom grid, this is the number of columns.
This property is used for keyboard navigation with the arrow keys.
Default: 1.
optional enabled: DynamicValue<boolean>;
optional label: DynamicValue<string>;
submenu: Readonly<MenuItem[]>;
optional submenuClass: string;
The class applied to the submenu container.
optional tooltip: DynamicValue<string>;
optional type: "submenu";
optional visible: DynamicValue<boolean>;
type MenuItemType = "command" | "divider" | "heading" | "submenu";
The type of a menu item:
command
: a command that can be selected and executeddivider
: a visual separatorheading
: a heading, not selectable. If following items (until next divider or heading) are not visible, the heading is not visible either.submenu
: a submenu
optional backdrop: string;
optional container: string;
optional id: string;
optional markup: string;
optional rows: Partial<VirtualKeyboardKeycap>[][];
optional style: string;
This interface is implemented by:
VirtualKeyboard
: when the browsing context is a top-level documentVirtualKeyboardProxy
: when the browsing context is an iframe
readonly boundingRect: DOMRect;
readonly isShifted: boolean;
readonly normalizedLayouts: VirtualKeyboardLayoutCore & {
layers: NormalizedVirtualKeyboardLayer[];
}[];
This property is the "expanded" version of the layouts
property.
It is normalized to include all the default values for the properties
of the layout and layers.
originValidator: OriginValidator;
Specify behavior how origin of message from postMessage should be validated.
Default: "none"
targetOrigin: string;
Specify the targetOrigin
parameter for postMessage
to send control messages from parent to child frame to remote control of
mathfield component.
Default: globalThis.origin
visible: boolean;
set alphabeticLayout(value: AlphabeticKeyboardLayout): void
Layout of the alphabetic layers: AZERTY, QWERTY, etc...
set container(value: HTMLElement): void
Element the virtual keyboard element gets appended to.
When using full screen elements that contain mathfield, set this property to the full screen element to ensure the virtual keyboard will be visible.
Default: document.body
set editToolbar(value: EditToolbarOptions): void
Configuration of the action toolbar, displayed on the right-hand side.
Use "none"
to disable the right hand side toolbar of the
virtual keyboard.
get layouts(): readonly (
| VirtualKeyboardLayout
| VirtualKeyboardName)[]
set layouts(value:
| VirtualKeyboardLayout
| VirtualKeyboardName
| VirtualKeyboardLayout | VirtualKeyboardName[]
| readonly VirtualKeyboardLayout | VirtualKeyboardName[]): void
A layout is made up of one or more layers (think of the main layer and the shift layer on a hardware keyboard).
A layout has a name and styling information.
In addition, a layout can be represented as a standard name which
includes "numeric"
, "functions"
, "symbols"
, "alphabetic"
and `"greek".
*See mathfield/guides/virtual-keyboards | Guide: Virtual Keyboards
connect(): void
disconnect(): void
executeCommand(command): boolean
string
| [string
, ...any[]
]
getKeycap(keycap): Partial<VirtualKeyboardKeycap>
Some keycaps can be customized:
[left]
, [right]
, [up]
, [down]
, [return]
, [action]
,
[space]
, [tab]
, [backspace]
, [shift]
,
[undo]
, [redo]
, [foreground-color]
, [background-color]
,
[hide-keyboard]
,
[.]
, [,]
,
[0]
, [1]
, [2]
, [3]
, [4]
,
[5]
, [6]
, [7]
, [8]
, [9]
,
[+]
, [-]
, [*]
, [/]
, [^]
, [_]
, [=]
, [.]
,
[(]
, [)]
,
string
hide(options?): void
boolean
setKeycap(keycap, value): void
string
Partial
<VirtualKeyboardKeycap
>
show(options?): void
boolean
update(mf): void
MathfieldProxy
updateToolbar(mf): void
The content or selection of the mathfield has changed and the toolbar may need to be updated accordingly
MathfieldProxy
aside: string;
Markup displayed with the key label (for example to explain what the symbol of the key is)
class: string;
CSS classes to apply to the keycap.
tex
: use the TeX font for its label. Using the tex class is not necessary if using thelatex
property to define the label.shift
: a shift keysmall
: display the label in a smaller sizeaction
: an “action” keycap (for arrows, return, etc…)separator w5
: a half-width blank used as a separator. Other widths includew15
(1.5 width),w20
(double width) andw50
(five-wide, used for the space bar).bottom
,left
,right
: alignment of the label
command:
| string
| string[]
| [string, any]
| [string, any, any]
| [string, any, any, any];
Command to perform when the keycap is pressed
insert: string;
LaTeX fragment to insert when the keycap is pressed (ignored if command is specified)
key: string;
Key to insert when keycap is pressed
(ignored if command
, insert
or latex
is specified)
label: string;
The HTML markup displayed for the keycap
latex: string;
Label of the key as a LaTeX expression, also the LaTeX
inserted if no command
or insert
property is specified.
layer: string;
Name of the layer to shift to when the key is pressed
shift: string | Partial<VirtualKeyboardKeycap>;
Variant of the keycap when the shift key is pressed
stickyVariantPanel: boolean;
Open variants panel without long press and does not close automatically
tooltip: string;
variants:
| string
| (string | Partial<VirtualKeyboardKeycap>)[];
A set of keycap variants displayed on a long press
variants: [
'\\alpha', // Same label as value inserted
{ latex: '\\beta', label: 'beta' }
]
width: 0.5 | 1 | 1.5 | 2 | 5;
Width of the keycap, as a multiple of the standard keycap width
optional backdrop: string;
A CSS class name to customize the appearance of the background of the layer
optional container: string;
A CSS class name to customize the appearance of the container the layer
optional id: string;
A unique string identifying the layer
optional markup: string;
optional rows: (string | Partial<VirtualKeyboardKeycap>)[][];
The rows of keycaps in this layer
optional style: string;
The CSS stylesheet associated with this layer
readonly normalizedLayouts: VirtualKeyboardLayoutCore & {
layers: NormalizedVirtualKeyboardLayer[];
}[];
This property is the "expanded" version of the layouts
property.
It is normalized to include all the default values for the properties
of the layout and layers.
originValidator: OriginValidator;
Specify behavior how origin of message from postMessage should be validated.
Default: "none"
targetOrigin: string;
Specify the targetOrigin
parameter for postMessage
to send control messages from parent to child frame to remote control of
mathfield component.
Default: globalThis.origin
set alphabeticLayout(value: AlphabeticKeyboardLayout): void
Layout of the alphabetic layers: AZERTY, QWERTY, etc...
set container(value: HTMLElement): void
Element the virtual keyboard element gets appended to.
When using full screen elements that contain mathfield, set this property to the full screen element to ensure the virtual keyboard will be visible.
Default: document.body
set editToolbar(value: EditToolbarOptions): void
Configuration of the action toolbar, displayed on the right-hand side.
Use "none"
to disable the right hand side toolbar of the
virtual keyboard.
get layouts(): readonly (
| VirtualKeyboardLayout
| VirtualKeyboardName)[]
set layouts(value:
| VirtualKeyboardLayout
| VirtualKeyboardName
| VirtualKeyboardLayout | VirtualKeyboardName[]
| readonly VirtualKeyboardLayout | VirtualKeyboardName[]): void
A layout is made up of one or more layers (think of the main layer and the shift layer on a hardware keyboard).
A layout has a name and styling information.
In addition, a layout can be represented as a standard name which
includes "numeric"
, "functions"
, "symbols"
, "alphabetic"
and `"greek".
*See mathfield/guides/virtual-keyboards | Guide: Virtual Keyboards
getKeycap(keycap): Partial<VirtualKeyboardKeycap>
Some keycaps can be customized:
[left]
, [right]
, [up]
, [down]
, [return]
, [action]
,
[space]
, [tab]
, [backspace]
, [shift]
,
[undo]
, [redo]
, [foreground-color]
, [background-color]
,
[hide-keyboard]
,
[.]
, [,]
,
[0]
, [1]
, [2]
, [3]
, [4]
,
[5]
, [6]
, [7]
, [8]
, [9]
,
[+]
, [-]
, [*]
, [/]
, [^]
, [_]
, [=]
, [.]
,
[(]
, [)]
,
string
setKeycap(keycap, value): void
string
Partial
<VirtualKeyboardKeycap
>
type AlphabeticKeyboardLayout = "auto" | "qwerty" | "azerty" | "qwertz" | "dvorak" | "colemak";
type EditToolbarOptions = "none" | "default";
type NormalizedVirtualKeyboardLayout = VirtualKeyboardLayoutCore & {
layers: NormalizedVirtualKeyboardLayer[];
};
type OriginValidator = (origin) => boolean | "same-origin" | "none";
Specify behavior for origin validation when using the virtual keyboard.
Value | Description |
---|---|
"same-origin" |
The origin of received message must be the same of hosted window, instead exception will throw. |
(origin: string) => boolean |
The callback to verify origin to be expected validation. When callback return false value, message will rejected and exception will throw. |
"none" |
No origin validation for post messages. |
type VirtualKeyboardLayout = VirtualKeyboardLayoutCore &
| {
layers: (string | VirtualKeyboardLayer)[];
}
| {
rows: (string | Partial<VirtualKeyboardKeycap>)[][];
}
| {
markup: string;
};
optional displayEditToolbar: boolean;
If false, do not include the edit toolbar in the layout
optional displayShiftedKeycaps: boolean;
If false, keycaps that have a shifted variant will be displayed as if they don't
optional id: string;
A unique string identifying the layout
optional label: string;
A human readable string displayed in the layout switcher toolbar
optional labelClass: string;
optional tooltip: string;
A human readable tooltip associated with the label
type VirtualKeyboardMessage =
| {
action: "execute-command";
command: Selector | [Selector, ...any[]];
type: "mathlive#virtual-keyboard-message";
}
| {
action: "geometry-changed";
boundingRect: DOMRect;
type: "mathlive#virtual-keyboard-message";
}
| {
action: "synchronize-proxy";
alphabeticLayout: AlphabeticKeyboardLayout;
boundingRect: DOMRect;
editToolbar: EditToolbarOptions;
isShifted: boolean;
layers: Record<string, string | Partial<VirtualKeyboardLayer>>;
layouts: Readonly<(string | VirtualKeyboardLayout)[]>;
setKeycap: {
keycap: string;
value: Partial<VirtualKeyboardKeycap>;
};
type: "mathlive#virtual-keyboard-message";
}
| {
action: "update-setting";
alphabeticLayout: AlphabeticKeyboardLayout;
editToolbar: EditToolbarOptions;
layers: Record<string, string | Partial<VirtualKeyboardLayer>>;
layouts: Readonly<(
| VirtualKeyboardName
| VirtualKeyboardLayout)[]>;
setKeycap: {
keycap: string;
value: Partial<VirtualKeyboardKeycap>;
};
type: "mathlive#virtual-keyboard-message";
}
| {
action: "show" | "hide";
animate: boolean;
type: "mathlive#virtual-keyboard-message";
}
| {
action: | "connect"
| "disconnect"
| "proxy-created"
| "focus"
| "blur"
| "update-state"
| "update-toolbar";
type: "mathlive#virtual-keyboard-message";
};
type VirtualKeyboardMessageAction =
| "connect"
| "disconnect"
| "proxy-created"
| "execute-command"
| "show"
| "hide"
| "update-setting"
| "update-toolbar"
| "synchronize-proxy"
| "geometry-changed"
| "update-state"
| "focus"
| "blur";
type VirtualKeyboardName =
| "default"
| "compact"
| "minimalist"
| "numeric-only"
| "numeric"
| "symbols"
| "alphabetic"
| "greek";
type VirtualKeyboardPolicy = "auto" | "manual" | "sandboxed";
"auto"
: the virtual keyboard is triggered when a mathfield is focused on a touch capable device."manual"
: the virtual keyboard is not triggered automatically"sandboxed"
: the virtual keyboard is displayed in the current browsing context (iframe) if it has a defined container or is the top-level browsing context.
type KeyboardLayoutName =
| "apple.en-intl"
| "apple.french"
| "apple.german"
| "apple.spanish"
| "dvorak"
| "windows.en-intl"
| "windows.french"
| "windows.german"
| "windows.spanish"
| "linux.en"
| "linux.french"
| "linux.german"
| "linux.spanish";
See setKeyboardLayout
.
Name | Platform | Display name |
---|---|---|
"apple.en-intl" |
Apple | English (International) |
"apple.french" |
Apple | French (AZERTY) |
"apple.german" |
Apple | German (QWERTZ) |
"dvorak" |
English (Dvorak) | |
"windows.en-intl" |
Windows | English (International) |
"windows.french" |
Windows | French (AZERTY) |
"windows.german" |
Windows | German (QWERTZ) |
"linux.en" |
Linux | English |
"linux.french" |
Linux | French (AZERTY) |
"linux.german" |
Linux | German (QWERTZ) |
function setKeyboardLayout(name): void
Change the current physical keyboard layout.
Note that this affects some keybindings, but not general text input.
If set to auto
the keyboard layout is guessed.
"auto"
| KeyboardLayoutName
function setKeyboardLayoutLocale(locale): void
Change the current physical keyboard layout to a layout that matches the specified locale, if one is available.
Note that this affects some keybindings, but not general text input.
string
type StaticRenderOptions = Partial<LayoutOptions> & {
asciiMath: {
delimiters: {
display: string[];
inline: string[];
};
};
ignoreClass: string;
processClass: string;
processMathJSONScriptType: string;
processScriptType: string;
readAloud: boolean;
renderAccessibleContent: string;
skipTags: string[];
TeX: {
className: {
display: string;
inline: string;
};
delimiters: {
display: [string, string][];
inline: [string, string][];
};
processEnvironments: boolean;
};
};
optional ignoreClass: string;
A string used as a regular expression of class names of elements whose content will not be scanned for delimiter
Default: "tex2jax_ignore"
optional processClass: string;
A string used as a regular expression of class names of elements whose content will be scanned for delimiters, even if their tag name or parent class name would have prevented them from doing so.
Default: "tex2jax_process"
optional processMathJSONScriptType: string;
<script>
tags with this type will be processed as MathJSON.
Default: "math/json"
optional processScriptType: string;
<script>
tags with this type will be processed as LaTeX.
Default: "math/tex"
optional readAloud: boolean;
If true, generate markup that can be read aloud later using speak
Default: false
optional renderAccessibleContent: string;
The format(s) in which to render the math for screen readers:
"mathml"
MathML"speakable-text"
Spoken representation
You can pass an empty string to turn off the rendering of accessible content.
You can pass multiple values separated by spaces, e.g "mathml speakable-text"
Default: "mathml"
optional skipTags: string[];
An array of tag names whose content will not be scanned for delimiters
(unless their class matches the processClass
pattern below).
Default: ['math-field', 'noscript', 'style', 'textarea', 'pre', 'code', 'annotation', 'annotation-xml']
function renderMathInDocument(options?): void
Transform all the elements in the document body that contain LaTeX code into typeset math.
Caution
This is a very expensive call, as it needs to parse the entire DOM tree to determine which elements need to be processed. In most cases this should only be called once per document, once the DOM has been loaded.
To render a specific element, use renderMathInElement()
import { renderMathInDocument } from 'https://esm.run/mathlive';
// Alternatively, you can use the **unpkg** CDN to load the library
// import { renderMathInDocument } from 'https://unpkg.com/mathlive?module';
renderMathInDocument();
function renderMathInElement(element, options?): void
Transform all the children of element
that contain LaTeX code
into typeset math, recursively.
An HTML DOM element, or a string containing the ID of an element.
string
| HTMLElement
import { renderMathInElement } from 'https://esm.run/mathlive';
renderMathInElement("formula");
optional after: string;
optional arg: string;
optional before: string;
code: T;
optional latex: string;
type ParserErrorCode =
| "unknown-command"
| "invalid-command"
| "unbalanced-braces"
| "unknown-environment"
| "unbalanced-environment"
| "unbalanced-mode-shift"
| "missing-argument"
| "too-many-infix-commands"
| "unexpected-command-in-string"
| "missing-unit"
| "unexpected-delimiter"
| "unexpected-token"
| "unexpected-end-of-string"
| "improper-alphabetic-constant";
Error codes returned by the mf.errors
property.
unknown-command |
There is no definition available for this LaTeX command, e.g. \zin
|
unknown-environment |
There is no definition available for this environment, e.g. \begin{foo}
|
invalid-command |
This command is not valid in the current context (e.g. text command in math mode) |
unbalanced-braces |
There are too many or too few { or }
|
unbalanced-environment |
An environment was open but never closed (\begin{array} ) or the \end command does not match the \begin command (\begin{array*}\end{array} ) |
unbalanced-mode-shift |
A $ , $$ , \( or \[ was not balanced |
missing-argument |
A required argument is missing, e.g. \frac{2}
|
too-many-infix-commands |
A group can include only one infix command (i.e. \choose , \atop ). In general it's best to avoid infix commands. |
unexpected-command-in-string |
A command expected a string argument, but there was a command instead |
missing-unit |
An argument requiring a dimension was missing an unit. |
unexpected-delimiter |
An invalid symbol or command was used as a delimiter. |
unexpected-token |
An unexpected character was encountered. |
unexpected-end-of-string |
The end of the string was reached, but some required arguments were missing. |
improper-alphabetic-constant |
The alphabetic constant prefix ` was not followed by a letter or single character command. |
function convertAsciiMathToLatex(ascii): string
Convert an AsciiMath string to a LaTeX string.
convertAsciiMathToLatex("1/2");
// -> "\\frac{1}{2}"
string
function convertLatexToAsciiMath(latex, parseMode): string
Convert a LaTeX string to a string of AsciiMath.
convertLatexToAsciiMath("\\frac{1}{2}");
// -> "1/2"
string
ParseMode
= 'math'
function convertLatexToMarkup(text, options?): string
Convert a LaTeX string to a string of HTML markup.
:::info[Note]
This function does not interact with the DOM. It does not load fonts or inject stylesheets in the document. It can safely be used on the server side. :::
To get the output of this function to correctly display
in a document, use the mathlive static style sheet by adding the following
to the <head>
of the document:
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/mathlive/mathlive-static.css"
/>
or
<link
rel="stylesheet"
href="https://unpkg.com/mathlive/mathlive-static.css"
/>
string
A string of valid LaTeX. It does not have to start
with a mode token such as $$
or \(
.
Partial
<LayoutOptions
>
function convertLatexToMathMl(latex, options): string
Convert a LaTeX string to a string of MathML markup.
string
A string of valid LaTeX. It does not have to start
with a mode token such as a $$
or \(
.
boolean
If true, add an "extid"
attribute
to the MathML nodes with a value matching the atomID
. This can be used
to map items on the screen with their MathML representation or vice-versa.
function convertLatexToSpeakableText(latex): string
Convert a LaTeX string to a textual representation ready to be spoken
string
A string of valid LaTeX. It does not have to start
with a mode token such as a $$
or \(
.
console.log(convertLatexToSpeakableText('\\frac{1}{2}'));
// 'half'
function convertMathJsonToLatex(json): string
Convert a MathJSON expression to a LaTeX string.
convertMathJsonToLatex(["Add", 1, 2]);
// -> "1 + 2"
function validateLatex(s): LatexSyntaxError[]
Check if a string of LaTeX is valid and return an array of syntax errors.
string
type Expression =
| number
| string
| {}
| [Expression, ...Expression[]];
const version: {
mathlive: string;
};
Current version: 0.105.2
The version string of the SDK using the semver convention:
MAJOR
.MINOR
.PATCH
MAJOR
is incremented for incompatible API changesMINOR
is incremented for new featuresPATCH
is incremented for bug fixes
import ChangeLog from '@site/src/components/ChangeLog';
## Coming Soon- Using the kebab version of commands (for example
"select-all"
instead of"SelectAll"
) would incorrectly result in a runtime error.
- #2526 In the virtual keyboard, the keycap text over CSS variables was not displayed correctly.
- #2567 Avoid potential race condition when changing the focus of the mathfield.
- #2638, #2479 Fragments that were styled with some color were not rendered correctly when the mathfield was not focused.
- #2669 If a page had multiple mathfields, when using the suggestion popover, the suggestion popover would be inserted in the wrong mathfield.
- #2584 In some cases, a menu item could get inadvertently selected when when brining up the menu.
- #2673 When using the CJS version of the library, the height of the virtual keyboard was not correctly calculated.
- #2666 In some cases, the state of the Undo/Redo buttons could get out of sync with the state of the mathfield.
- #2667 The edit toolbar was not displayed in the alphabetic keyboard layout.
- Accessibility: Improved support for the high-contrast mode.
- There is a new CSS variable to control the z-index of the suggestion popover:
--suggestion-zindex
. This allows the suggestion popover to be displayed above other elements on the page. - Added support for the
\strut
and\mathstrut
commands. These commands are used to insert a strut, which is an invisible element that takes up space in the math expression. This is useful for aligning expressions or for creating space between elements. - #2662 When the command popover is displayed, pressing the Return key will insert the command in the mathfield and close the popover.
- #2658 Improved localization for Italian.
- #2671 When inserting a command with an argument with the suggestion popover, position the cursor inside the argument.
In order to support alternate CDNs, in particular jsdelivr
, the file layout of
the npm package has changed. The files that were previously in the ./dist/
directory are now in the root of the package. This should not affect most users,
but if you are importing the library or auxiliary files from the dist
directory, you will need to update your paths.
To use jsdelivr
, use:
import { MathfieldElement } from "https://esm.run/mathlive";
or:
<script defer src="https://cdn.jsdelivr.net/npm/mathlive"></script>
-
#2647, #2634, #2562 Some accents (
\hat{}
,\vec{}
) where not rendered correctly in some cases. -
#2635 In Chrome (and Firefox), clicking on the padding area of the mathfield would not result in the focus getting into a zombie state and keyboard event no longer being dispatched.
- #2588 With Chrome 133+ input with the physical keyboard was disabled after showing the virtual keyboard.
- Improved support for the
jsdelivr
CDN. To use it, use:
import { MathfieldElement } from "https://esm.run/mathlive";
- #2628 Attempting to delete an empty line in a multiline environment would not delete the line.
- #2585 In some cases, the arguments of a macro were not serialized correctly. This could happen when using a macro in conjunction with a inline shortcut.
- #2586 The
\pdiff{}{}
command was not properly serialized to LaTeX.
As a reminder, if you are handling untrusted input, you should consider using
the MathfieldElement.createHTML()
method to sanitize content. The
createHTML()
method follows the recommendations from the
Trusted Type specification.
For example, using the DOMPurify library (there are other HTML sanitizers available):
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.2.3/purify.min.js"></script>
MathfieldElement.createHTML = (html) => DOMPurify.sanitize(html);
-
security advisory Untrusted input could be used to inject arbitrary HTML or JavaScript code in a page using a mathfield or math content rendered by the library, if the content included an
\htmlData{}
command with maliciously crafted input and no DOM sanitizer was used.The content of the
\htmlData{}
command is now sanitized and the 🚫 emoji is displayed instead in the mathfield if the content is unsafe. When usingconvertLatexToMarkup()
, an exception is thrown. -
The
\href{}{}
command now only allows URLs with thehttp
orhttps
protocol.
-
Generate only standard trigonometric functions, i.e. those available in the
amsmath
package. Use\operatorname{}
for the others. The standard commands are:\arccos
\arcsin
\arctan
\arg
\cos
\cosh
\cot
\coth
\csc
\sec
\sin
\sinh
\tan
\tanh
-
Added support for
\dddot
and\ddddot
commands. -
#2573 The
\operatorname{}
command when round-tripped would incldue an extraneous\mathrm{}
command. -
#2132, #2548 Improved handling of multi-line mathfields. To use a multi-line mathfield, include a multi-line environment:
\displaylines{}
: single column of left-aligned equationsgather
: single column of centered equationsmultline
: centered equations with the first line aligned left and the last line aligned to the rightalign
: two columns, the first column right-aligned, the second column left-aligned; used for one equation per linesplit
: two columns of equations, the first column right-aligned, the second column left-aligned; used for a single equation split over multiple lines
For example:
<math-field>\displaylines{x=1 \\y = 2}</math-field>
<math-field>\begin{align}
f(0) &= 1 \\
f(x + 1) &= f(x-1) + f(x)
\end{align}
</math-field>
-
When in a multi-line environment, the Return key will move to the next line. The Backspace key will delete the current line if the cursor is at the beginning of the line. Note that no placeholder is inserted on a new line: the line is simply blank.
-
The Add Row Before, Add Row After, Add Column Before, Add Column After, Delete Row and Delete Columns commands are available in the context menu when the cursor is inside a matrix. They are not available in multi-line environments.
-
#2574 The commands
\coloneq
,\Coloneq
,\Coloneqq
,\eqcolon
and\Eqcolon
were mapped to incorrect symbols (some of them used obsolete definitions of those commands from the mathtools package that changed in the Summer of 2022). They are now correctly mapped to the corresponding symbols. -
#2576 The command
\perp
was mapped to the wrong symbol (U+22A5). It is now mapped to the correct symbol (U+27C2) -
Improved ASCIIMath serialization.
- #2530 The AsciiMath
1/2
is now parsed as\frac{1}{2}
- The
\displaylines
command is now correctly parsed as a command with an argument, not as a group command.
- #2550 The subpath exports in the main package.json have been updated to comply with Node.js's subpath patterns, which utilize "direct static matching and replacement.
-
#2554 Option for sticky virtual keyboard variant panel
When long pressing a key on the virtual keyboard, a variant panel is displayed that offers alternatives (variants) for that key. The panel is only displayed while your finger is pressing the key (like a smartphone keyboard). This new options allows the variant panel to remain displayed even if you lift your finger from the screen.
Add the
stickyVariantPanel
property to a virtual keyboard keycap definition to make the variant panel sticky.See
./examples/sticky-variant-panel/
for an example.
- Correctly display the caret following a
\mathop{}
command. - #2540 When using
renderMathInElement()
some white space was occasionally incorrectly removed. - #2545 (?) Use
\rightarrow
instead of\rarr
in the virtual keyboard. - #2543 The
MathfieldElement.fractionNavigationOrder
was not respected when navigating in a fraction with the arrow keys. - #2251 Fixed the serialization of
\displaylines{}
- #2533 When using the virtual keyboard to insert a character with a blackboard style followed by a non-alphabetic symbol without a blackboard style, the second symbol would incorrectly be serialized with a blackboard style.
- In some cases, the
placeholder
attribute would not be displayed when the mathfield was empty. - When using static math, the font-familly for text content was not correctly inherited from the parent element.
- In some cases, the inherent style of a macro could get overriden. For example typing the "RR" inline shortcut resulted in an unstyled R instead of the expected blackboard R.
- The properties
mathVirtualKeyboard.actionKeycap
,mathVirtualKeyboard.shiftKeycap
,mathVirtualKeyboard.backspaceKeycap
, andmathVirtualKeyboard.tabKeycap
have been removed. Use the more generalmathVirtualKeyboard.setKeycap()
method to customize these keycaps, that ismathVirtualKeyboard.setKeycap('[action]', {...})
etc...
-
Macros can now be specified with
renderMathInElement()
andrenderMathInDocument()
using themacros
option. For example:renderMathInElement(element, {macros: {RR: '\\mathbb{R}'}})
-
Performance improvements for pages with many mathfields. The initial rendering can be up to 2x as fast.
-
Some keycaps in the virtual keyboard can be customized without having to define an entire virtual keyboard layout.
The
mathVirtualKeyboard.getKeycap()
give access to the definition of special keycaps andmathVirtualKeyboard.setKeycap()
can be used to change that definition.The keycaps are one of these special shortcuts:
[left]
,[right]
,[up]
,[down]
,[return]
,[action]
,[space]
,[tab]
,[backspace]
,[shift]
,[undo]
,[redo]
,[foreground-color]
,[background-color]
,[hide-keyboard]
,[.]
,[,]
,[0]
,[1]
,[2]
,[3]
,[4]
,[5]
,[6]
,[7]
,[8]
,[9]
,[+]
,[-]
,[*]
,[/]
,[^]
,[_]
,[=]
,[.]
,[(]
,[)]
For example, to change the LaTeX inserted when the multiplication key is pressed use:
mathVirtualKeyboard.setKeycap('[*]', {latex: '\\times'});
- #2455 Serialization to ASCII Math of brackets and braces is now correct.
- When using Chrome in some locale (such as
es-419
), the context menu would not be displayed. - When the
MathfieldElement.isFunction
handler is updated, re-render all the mathfields on the page to take it into account. - #2415 A content change event is now dispatched when the value of the mathfield is changed as a result of switch from LaTeX mode to math mode by changing the selection.
- Dispatch a
contextmenu
event any time the context menu is about to be displayed. This allows the event to be canceled. - #2413 When setting the
alphabeticLayout
, the current keyboard would not be updated in some cases. - #2412 The serialization of some expressions to LaTeX could result in some
spaces being omitted. For example,
\lnot p
would serialize as\lnotp
. - #2403 The virtual keyboard Keycap Variants panel was positioned incorrectly when the page used a RTL layout direction.
- In the virtual keyboard, the background of the variant panel was sometimes displayed transparently.
- #2402 Characters inserted after a
\mathbb{}
command were not styled correctly. - The
math-virtual-keyboard-command
event was not dispatched when a mathfield was focused and a keycap was pressed. - There are now CSS selectors to customize the size of glyphs in the virtual
keyboard (shift, enter, etc...):
--keycap-glyph-size
--keycap-glyph-size-lg
--keycap-glyph-size-xl
- #2397 When a
beforeinput
event was canceled, the text would still be inserted when using the physical keyboard. - #2398 When a placeholder was the only element in a group, i.e.
{\placeholder{}}
, the placeholder was not automatically selected.
-
#2396 Pressing the arrow keys in the virtual keyboard would not move the selection in the mathfield and display a runtime error in the console.
-
#2392 Pressing the backspace key after typing several digits would delete all the digits.
-
#2395 Added a
dispatchEvent
command which can be attached to a custom keycap.Its first argument is the name of the dispatched event, and the second argument is an object with the
detail
property, which is the data associated with the event.{ label: "✨", command: "dispatchEvent('customEvent', {detail: 'some data'})" }
To handle the event, add an event listener to the mathfield element:
mf.addEventListener('customEvent', (ev) => { console.log(ev.detail); });
-
The
mf.offsetFromPoint()
method has been renamedmf.getOffsetFromPoint()
-
The
mf.setCaretPoint()
method has been replaced withmf.position = mf.getOffsetFromPoint()
-
The
mf.scriptDepth()
andmf.hitboxFromOffset()
methodds have been replaced withmf.getElementInfo()
.The
getElementInfo()
method provides more information including any id that may have been applied with\htmlId{}
.It is useful from within a
click
handler to get more information about the element that was clicked, e.g.mf.getElementInfo(mf.getOffsetFromPoint(ev.clientX, ev.clientY))
The info returned is an object with the following properties:
export type ElementInfo = { /** The depth in the expression tree. 0 for top-level elements */ depth?: number; /** The bounding box of the element */ bounds?: DOMRect; /** id associated with this element or its ancestor, set with `\htmlId` or `\cssId` */ id?: string; /** HTML attributes associated with element or its ancestores, set with * `\htmlData` */ data?: Record<string, string | undefined>; /** The mode (math, text or LaTeX) */ mode?: ParseMode; /** A LaTeX representation of the element */ latex?: string; /** The style (color, weight, variant, etc...) of this element. */ style?: Style; };
The way bold is handled in LaTeX is particularly confusing, reflecting limitations of the text rendering technology of the time.
Various attempts have been made over the years to improve the rendering of bold, but this has resulted in inconsistent behavior. Furthermore, various implementations of LaTeX and LaTeX-like systems have implemented bold in different ways.
This release introduces a more consistent and intuitive handling of bold, although it may result in different rendering of some formulas compared to some implementations of LaTeX.
The original bold command in LaTeX is \mathbf
. This command renders its
argument using a bold variant of the current font. However, only letters and
numbers can be rendered by this command. It does not affect symbols, operators,
or greek characters.
For example, \mathbf{a+b}
will render as 𝐚+𝐛
, with the a
and b
in bold,
but the +
in normal weight. Characters rendered by \mathbf
are rendered
upright, even if they would have been rendered as italic otherwise.
The \boldsymbol
command is an alternative to \mathbf
that affects more
characters, including Greek letters and symbols. It does not affect the style of
the characters, so they remain italic if they were italic before. However, the
inter-character spacing and italic correction may not be rendered correctly.
The \bm
command from the bm
package is a more modern alternative that
affects even more characters. It also preserves the style of the characters, so
they remain italic if they were italic before. The inter-character spacing and
italic correction are handled correctly.
The \bm
command is recommended over \boldsymbol
and \mathbf
. However, it
is not part of the standard LaTeX distribution, so it may not always be
available.
When serializing to LaTeX, MathLive will now use \mathbf
when possible, and
fall back to \bm
when not. This should result in more consistent rendering of
bold text.
When parsing, MathLive will interpret both \mathbf
, \boldsymbol
and \bm
as
bold.
The bold style is now consistently inherited by sub-expressions.
Similarly, when applying a bold style using mf.applyStyle({weight: "bold"})
,
the bold attribute is applied to the entire selection, not just the letters and
numbers.
- #2375 The
switch-mode
command has two optionals arguments, a prefix and suffix. The prefix is inserted before the mode switch, and the suffix after. The command was behaving incorrectly. It now behaves as expected. - It is now possible to roundtrip between math and text mode. For example,
selecting a fraction
\frac{a}{b}
and pressingalt+shift+T
will convert the selection to(a)/(b)
. Pressingalt+shift+T
again will convert it back to\frac{a}{b}
. - When in LaTeX mode, changing the selection would sometimes unexpectedly exit LaTeX mode, for example after the Select All command. This has been fixed.
-
\href
The
\href{url}{content}
command, a MathJax extension that allows a link to be associated with some content, is now supported.Clicking on the content will open the link. By default, the link is opened in a new window, and only links with a HTTP, HTTPS or FILE protocol are allowed. This can be controlled by the new
MathfieldElement.openUrl
property. This property is a function with a single argument, the URL to be opened, that is called when the content of the\href
command is clicked on. -
Tooltip appearance
Added CSS variables to control the appearance of the toolip displayed with
\mathtip
and\texttip
:--tooltip-border
--tooltip-color
--tooltip-background-color
--tooltip-box-shadow
--tooltip-border-radius
.
-
The
maxMatrixCols
property has been added that specifies the maximum number of columns that a matrix may have. The default value is 10, which follows the default value from the amsmath package. The property applies to all of the matrix environments (matrix
,pmatrix
,bmatrix
, etc.). This property is also accessible via themax-matrix-cols
attribute. -
The virtual keyboard now supports variants for shifted-keys. This includes support for Swedish specific characters such as
å
,ä
, andö
and their uppercase variants. -
Accept
"true"
and"false"
as values for on/off attributes in the<math-field>
element, for example<math-field smart-fence="true">
. -
Added a
target
property (aMathfieldElement
) to theonMenuSelect
arguments. -
#2337 Added an option
MathfieldElement.restoreFocusWhenDocumentFocused
to control whether a mathfield that was previously focused regains focus when the tab or window regains focus. This is true by default and matches the previous behavior, and the behavior of the<textarea>
element. -
An alternate syntax for selectors with arguments. Selectors are used for example to associate actions with a keycap, such as
switchKeyboardLayer
. The previous syntax wascommand: ["switchKeyboardLayer", "alt-layer"]
, the new syntax iscommand: 'switchKeyboardLayer("alt-layer")'
. This is more concise and easier to read.
- #2387 When using a macro, the spacing around the macro was incorrect in some cases.
- #2370 The order of the
keydown
andinput
event is now consistent with the<textarea>
element. - #2369 After typing a shortcut, using the backspace key could result in unexpected behavior. Now, pressing the backspace key after a shortcut has been typed will undo the conversion of the shortcut.
- #2380 In some cases, when using the menu, some spurious focus/blur events would be dispatched.
- #2384 When using repeating decimals after a comma (i.e.
123{,}4(1)
), do not use a\left...\right
command in order to get the proper spacing. - #2349 The positioning of subscripts for extensible symbols, such as
\int
was incorrect. - #2326 The Cut and Copy commands in the context menu are now working correctly in Safari.
- #2309 When using styled text (e.g.
\textit{}
), the content could sometimes be serialized with an unnecessary\text{}
command, i.e.\text{\textit{...}}
. - #2376 When
smart-fence
was off, the{
and}
keys would not insert braces. - #2273 Using one of the Chinese locales would result in a runtime error.
- #2355 When pressing the down arrow key in
\sqrt[#?]{1}
from the#?
position, a runtime exception would occur. - #2298 When using screen readers, pressing the spacebar would not always correctly focus the mathfield.
- #2297 In some cases, when using touch input, the previously selected item in a context menu would appear to be selected.
- #2289 When changing the value of the mathfield, the selection is now preserved. In addition, when using a controlled component with React an unnecessary update is avoided.
- #2282 Don't display selection when the mathfield is not focused
- #2280 Handle better very deeply nested expressions
- #2261 When a style was applied to an empty range, the style was ignored.
- #2208 When setting a variant style (i.e. blackboard, fraktur, etc...) the style is no longer adopted by subsequent characters.
- #2104, #2260 When replacing the selection by typing, the new content would not always be correctly styled. The content now inherits the style of the selection, or the style of the insertion point if the selection is collapsed.
- Better handle the case where the mathlive library gets loaded before the DOM is constructed.
- On Safari, the Insert Matrix submenu was displayed incorrectly.
- When the mathfield is an iframe, the
before-virtual-keyboard-toggle
andvirtual-keyboard-toggle
events are now dispatched on thewindow.mathVirtualKeyboard
object of the iframe. This can be used to detect a request (and prevent) for the virtual keyboard to be displayed. - If the unknown in an expression was a complex identifier, such as
\mathcal{C}
it would not be displayed correctly in the "Solve for" menu. - The
\mathrlap
command was incorrectly rendering like\mathllap
.
- Added
StaticRenderOptions.TeX.className
to specify that an element with the specified class name should be rendered as a LaTeX formula. - #2273 Added a
--keycap-width
CSS variable to specify the width of a keycap in a virtual-keyboard. By default, if the CSS variable is not specified, the width of the keycap is calculated based on the width of the parent container. However, this requires browser that support thecq
CSS unit. If the browser does not support thecq
CSS unit, this CSS variable can be used to specify the width of the keycap. (See #2028, #2133) - #2255 Support for
gather*
environment - #2242 A virtual keyboard keycap can now include a tooltip for its shifted variant.
- When using some APIs such as
renderToMarkup()
orrenderToMathML()
in a server-side environment, a runtime error would occur. - When tabbing in a mathfield with multiple prompts, tab out of the mathfield when the last or first prompt is reached.
- **#2243##, **#2245** Unicode characters such as
²
orℂ
are now interpreted as their LaTeX equivalent only when in math mode. - #2237 The command
\iff
now renders correctly - #2246 Changing the
mf.value
property would not always update the value of the mathfield. - #2244 Worked around an issue in Safari on iOS where doing a double-tap on the virtual keyboard would result in the mathfield losing focus and the virtualy keyboard closing.
- #2252 At some viewport sizes, the integral sign in the symbols virtual keyboard would be clipped.
- #2235 Improved serialization to ASCIIMath.
- Avoid conflicts with some class names when rendering static math.
- When using
renderMathToElement()
orrenderMathInDocument()
, coalesce adjacent text nodes. - Correctly parse the
\cfrac
optional alignment argument - The commands
\bf
,\bfseries
,\mdseries
,\upshape
,\itshape
,\slshape
,\scshape
,\rmfamily
,\sffamily
,\ttfamily
are now interpreted correctly. - The command
\operatorname
is now spoken correctly - #2152 On Safari, fill-in-the-blank prompts containing a fraction were rendered incorrectly.
To add a macro use mf.macros = {...mf.macros, ...}
.
If you do not include the ...mf.macros
expression, all the standard macros will be
turned off.
The example below will define a new command, \average
, which will be
replaced by \operatorname{average}
, that is displayed as a single unit
using an upright font.
Try changing \operatorname
to \mathbf
to see the difference.
:::html
<math-field id="mf">\average([2, 4, 8])</math-field>
:::js
const mf = document.getElementById("mf");
mf.macros = { ...mf.macros,
average: '\\operatorname{average}',
};
You can use standard LaTeX commands in the definition of a macro. For example,
the following macro definition uses the \,
and \;
commands to insert
horizontal spacing and {}^
to place the \prime
command on the subscript
line.
mf.macros = { ...mf.macros,
minutes: "\\,{}^\\prime\\;",
seconds: "\\,\\doubleprime\\;",
};
The macro definition can contain up to eight arguments, represented by #1
to #9
.
:::js
const mf = document.getElementById("mf");
mf.macros = {...mf.macros,
smallfrac: "{}^{#1}\\!\\!/\\!{}_{#2}",
};
:::html
<math-field id="mf">\smallfrac{5}{7}+\frac{5}{7}</math-field>
By default, a macro command behaves as a group whose subcomponents cannot be
modified. This behavior can be controlled using the captureSelection
flag
in the expanded definition of a macro.
To define a macro whose content is selectable and editable set
captureSelection
to false
.
:::js
const mf = document.getElementById("mf");
mf.macros = {...mf.macros,
smallfrac: {
args: 2,
def: '{}^{#1}\\!\\!/\\!{}_{#2}',
captureSelection: false,
},
};
:::html
<math-field id="mf">\scriptCapitalE=\smallfrac{5}{7}+\frac{5}{7}</math-field>
To remove a macro set its definition to undefined:
:::js
const mf = document.getElementById('mf');
mf.macros = {...mf.macros, diamonds: undefined };
:::html
<math-field id="mf">\diamonds</math-field>
By defining a new macro, a new LaTeX command is added to the dictionary of commands that can be used in a LaTeX expression.
To input a macro, type \ followed by the macro name, then RETURN
Custom macros are also included in the value of the mathfield
expressed as a LaTeX string (mf.value
).
It may also be convenient to associate the macro with an inline shortcut. Inline shortcuts can be typed without having to enter the LaTeX editing mode (without having to type the \ key).
To define an associated inline shortcut, use the inlineShortcuts
option.
:::js
const mf = document.getElementById('mf');
//
mf.macros = {...mf.macros,
// This means that the command macro `\minutes`
// will be replaced with `\,{}^\\prime\\;`
minutes: '\\,{}^\\prime\\;',
seconds: '\\,\\doubleprime\\;',
};
//
mf.inlineShortcuts = {...mf.inlineShortcuts,
// This means that typing the inline shortcut
// "minutes" will insert the command "\minutes"
minutes: '\\minutes',
seconds: '\\seconds',
};
:::html
<math-field id="mf">
3\minutes 15\seconds
</math-field>
To view the available macros, inspect the macros
property:
:::js
const mf = document.getElementById('mf');
console.log(mf.macros);
:::html
<math-field id='mf'>x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}</math-field>
To turn off all macros, use mf.macros = {}
.
The mathfield library includes some utility functions to convert between various formats. These utility functions can be used without a mathfield. In fact, they do not require a browser environment at all, and can be used in a Node.js environment.
They are available as a Service Side Render (SSR) package which can be imported as follows:
import * from 'mathlive/ssr';
To convert LaTeX to HTML, use the convertLatexToMarkup()
function.
import { convertLatexToMarkup } from 'mathlive';
console.log(convertLatexToMarkup('x^2 + y^2 = z^2'));
To convert LaTeX to MathML, use the latexToMathML()
function.
import { convertLatexToMathMl } from 'mathlive';
console.log(convertLatexToMathMl('x^2 + y^2 = z^2'));
To convert LaTeX to spoken text, use the convertLatexToSpeakableText()
function.
import { convertLatexToSpeakableText } from 'mathlive';
console.log(convertLatexToSpeakableText('x^2 + y^2 = z^2'));
To convert LaTeX to AsciiMath, use the convertLatexToAsciiMath()
function.
import { convertLatexToAsciiMath } from 'mathlive';
console.log(convertLatexToAsciiMath('x^2 + y^2 = z^2'));
To convert MathJson to LaTeX, use the convertMathJsonToLatex()
function.
import { convertMathJsonToLatex } from 'mathlive';
console.log(convertMathJsonToLatex(["Add", "x", "y"]));
To convert AsciiMath to LaTeX, use the convertAsciiMathToLatex()
function.
import { asciiMathToLatex } from 'mathlive';
console.log(convertAsciiMathToLatex('x^2 + y^2 = z^2'));
To render math contained in a document as a static (non-editable) formula,
call renderMathInDocument()
at the
end of your document, or in a DOMContentLoaded
event handler.
<script defer type="module">
window.addEventListener('DOMContentLoaded', () =>
import('https://esm.run/mathlive').then((mathlive) =>
mathlive.renderMathInDocument()
)
);
</script>
By default, any LaTeX code in the text element of a DOM element that is enclosed with the following delimiters will be rendered as math:
-
\[
...\]
or$$
...$$
-- rendered in Display Style (CSS display block) -
\(
...\)
-- rendered in Text Style (CSS display inline)
<h1>Taxicab Number</h1>
<p>The second taxicab number
is \\(1729 = 10^3 + 9^3 = 12^3 + 1^3\\)
</p>
More complex expressions can be wrapped in a <script>
tag. One of the
benefits of this approach is that the browser will not attempt to display the
content of the <script>
tag before it is typeset, avoiding an unsightly flash
of code on screen.
To render LaTeX code, use <script type="math/tex">
To render MathJSON, use <script type="math/json">
To render the formula inline, append ; mode=text
to the type.
If no mode is provided, or mode=display
, the display (block) style is
used.
<h1>Quadratic roots</h1>
<script type="math/json"> ["Add",
["Multiply", "a", ["Square", "x"]]],
["Multiply", "b", "x"],
"c"
]
</script>
<script type="math/tex; mode=text">
= a
\left( x - \frac{-b + \sqrt {b^2-4ac}}{2a} \right)
\left( x - \frac{-b - \sqrt {b^2-4ac}}{2a} \right)
</script>
The following DOM elements are ignored for conversion: <noscript>
,
<style>
, <textarea>
, <pre>
, <code>
, <annotation>
and <annotation-xml>
.
If you dynamically generate content, call renderMathInElement(element)
to
render your element after the page has been loaded. This is a recursive call
that will be applied to element
and all its children.
To render again elements or a whole document that has already been rendered,
call renderMathInElement()
and renderMathInDocument()
again. This is
useful when a change in the environment requires the layout to be updated.
To customize the behavior of the renderMathInElement()
and renderMathInDocument()
functions pass an optional options
object literal:
skipTags
: an array of tag names whose content will not be scanned for delimitersprocessScriptType
:<script>
tags of the indicated type will be processed while others will be ignored. Default: "math/tex".ignoreClass
: a string used as a regular expression of class names of elements whose content will not be scanned for delimiters ("tex2jax_ignore"
by default)processClass
: a string used as a regular expression of class names of elements whose content will be scanned for delimiters, even if their tag name or parent class name would have prevented them from doing so. ("tex2jax_process"
by default)TeX.processEnvironments
: if false, math expression that start with\begin{
will not automatically be rendered. (true by default)TeX.delimiters.inline
andTeX.delimiters.display
arrays of delimiters that will trigger a render of the content in 'textstyle' or 'displaystyle' style, respectively.
renderMathInElement(document.getElementById('formulas'), {
// Elements with a class of "instruction" or "source"
// will be skipped
ignoreClass: 'instruction|source',
TeX: {
delimiters: {
// Allow math formulas surrounded by $...$ or \(...\)
// to be rendered as inline (textstyle) content.
inline: [
['$', '$'],
['\\(', '\\)'],
],
display: [],
},
},
});
When a math formula is displayed as a static element using
renderMathInDocument()
, the formula is transformed into some static markup.
As a result, only the markup content can be selected, not the underlying
LaTeX formula. Selection of a portion of the formula may also lead to
unexpected results.
If preserving the ability to select a formula is important, consider using a read-only mathfield instead.
To create a read-only mathfield, add the read-only
attribute to a <math-field>
element.
:::html
<style>
math-field[read-only] {
border: none;
background-color: transparent;
}
</style>
<p>The solution of the equation is
<math-field read-only style="display:inline-block">
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
</p>
To speak the formula or a portion of it, use these keyboard shortcuts:
- alt/⌥ + ctrl + ⇡: speak the entire formula
- alt/⌥ + ctrl + ⇣: speak the selection
To programatically trigger speech output, use:
mf.executeCommand('speak');
The command above will speak the entire formula. To speak a subset of the formula use:
mf.executeCommand(['speak', 'selection');
The options to specify the speech "scope" are:
all |
the entire formula |
selection |
the selection portion of the formula |
left |
the element to the left of the selection |
right |
the element to the right of the selection |
group |
the group (numerator, root, etc..) the selection is in |
parent |
the parent of the selection |
To get a textual representation of a spoken description of the formula, use
the spoken-text
format:
mf.getValue('spoken-text');
There are two aspects that can be configured independently:
-
Speech Rules: the set of rules use to produce readable text from a math expression.
-
Text-to-Speech engine: the software used to transform the readable text produced by the speech rules into sound. By default, the TTS engine provide by the operating system will be used, but you can use the Amazon Cloud TTS engine as well.
A set of speech rules define how a math formula is transformed to speakable text.
To use the built-in speech rules, set MathfieldElement.textToSpeechRules
to "mathlive"
.
Another set of speech rules supported are the SRE speech rules from Volker Sorge
To use the SRE speech rules:
- Include the browser version of the SRE JavaScript file in your project. You can download it on GitHub
- Set
MathfieldElement.textToSpeechRules
to"sre"
.
To configure SRE, set the MathfieldElement.textToSpeechRulesOptions
property.
For example:
MathfieldElement.textToSpeechRulesOptions = {
domain: 'mathspeak', // 'mathspeak' or 'chromevox'
ruleset: 'mathspeak-brief', // 'mathspeak-default',
// 'mathspeak-brief', 'mathspeak-sbrief', 'chromevox-short',
// 'chromevox-default' or 'chromevox-alternative'
};
To use the local (built-in, OS specific) TTS engine, set MathfieldElement.speechEngine
to "local"
.
There is great variation between platforms (and browsers) on the quality of the TTS engine. However, it can be used even when offline, while the Amazon TTS engine offers higher quality and better consistency, but it does require a network connection.
- Include the AWS SDK for JavaScript in your app. See here for details. This may be as simple as adding this:
<head>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.657.0.min.js"></script>
<script>
AWS.config.region = 'eu-west-1';
AWS.config.accessKeyId = 'YOUR-KEY';
AWS.config.secretAccessKey = 'YOUR-SECRET';
</script>
</head>
See npm for the latest version.
-
To get the necessary keys, follow these instructions
2.1 Create a custom policy in your AWS console with action: Read SynthesizeSpeech and a request condition of a referrer with a StringEquals to your domain, e.g. 'https://example.com/*'
2.2 Create a group, and associated it with the policy above
2.3. Create a new user, for example the name of your app. Give it 'programmatic access' and associate it with the group above
2.4 At the end of the creation, you will be provided by the access key and the secret access key.
Carefully consider how to handle the access and secret access keys. With the setup above they are somewhat restricted to a domain, however, they could be abused if accessed by an unauthorized user. To prevent this, you could require users to authenticate and use AWS Cognito.
To configure the format of the speech output engine, use the MathfieldElement.textToSpeechMarkup
. Set it to:
"ssml"
to request an output using the SSML markup language. Both SRE and the Mathfield rules can produce this format."mac"
to request an output using Mac OS speech markup, e.g. '[[slc 150]]'. This format can only be used on Mac OS (and may not work will all browsers). On platforms other than Mac OS, this option does nothing.""
(empty string) to request no markup.
The Amazon TTS engine supports SSML, and it is recommended to use this option for the highest quality.
title: Changelog - Mathfield sidebar_label: Changelog slug: /mathfield/changelog/ toc_max_heading_level: 2
import ChangeLog from '@site/src/components/ChangeLog';
--- date: Last Modified title: Math Virtual Keyboard id: virtual-keyboard slug: /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.
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**.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.
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.
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.
The **Mathfield Context Menu** provides a set of commands to perform common operations on a mathfield.
To display the context menu:
- Right-click on the mathfield
- Long press on the mathfield
- Tap on the menu toggle (hamburger icon) in the mathfield
- Press the ALT/OPTION+SPACE, FN+F10 or MENU key on a physical keyboard
The context menu is fully accessible. It can be navigated using the keyboard, and the menu items are announced by screen readers.
To navigate the context menu, use the arrow keys.
An item can also be selected by typing some of the letters of its label.
The default context menu has a set of commands that are useful for most applications, but you can customize the menu by adding or removing commands as needed.
To select which menu items are displayed, use the filter()
method on
the mf.menuItems
property.
For example, to omit all commands related to the Compute Engine (such as Evaluate, Simplify and Solve), you can filter the menu items by their id:
mf.menuItems = mf.menuItems.filter(item => !item.id.startWith('ce-'));
:::warning
The mf.menuItems
property is a read-only property. It returns a copy of the
original array of menu items.
Do not modify the value of the elements of mf.menuItems
directly. This will
result in a runtime error.
For example, do not use mf.menuItems[0].visible = false
.
:::
To replace the context menu with your own, set the mf.menuItems
property.
The menuItems
property is an array of menu items.
Each menu item is an object with the following properties:
type
: one of"command"
,"divider"
,"submenu"
,"checkbox"
,"radio"
. The default is"command"
.label
: The label to display for the menu item. This can be a string literal or a function that returns a string. If a function is provided, it will be called to update the label whenever the menu is displayed or when the keyboard modifiers change. The value of the string is interpreted as HTML markup.ariaLabel
andariaDetails
: If provided, these will be used to set thearia-label
andaria-details
attributes of the menu item, which can be used by screen readers. Like thelabel
property they can be either a string literal or a function that returns a string.visible
,enabled
,checked
are status flags that can be set totrue
orfalse
to control the visibility, enabled state and checked state of the menu item.id
: A unique identifier for the menu item. This is the value that will be passed to themenu-select
event when the menu item is selected.data
: An arbitrary data payload associated with the menu item, if any.submenu
: If the type is"submenu"
, an array of menu items to display when the menu item is selected.onMenuSelect
: A function handler that is called when the menu item is selected.
mf. menuItems = [
{
label: 'Copy',
onMenuSelect: () => console.log('Copy')
},
{
label: 'Paste',
onMenuSelect: () => console.log('Paste')
},
{
type: 'divider'
},
{
label: 'Submenu',
submenu: [
{
label: 'Submenu 1',
onMenuSelect: () => console.log('Submenu 1')
},
{
label: 'Submenu 2',
onMenuSelect: () => console.log('Submenu 2')
}
]
},
];
To add a menu item, use the spread operator (...
) to create a new array
of menu items, and add the new menu item to the copy of the original array.:
mf.menuItems = [
{
label: "Cancel",
visible: () =>
mf.isSelectionEditable && !mf.selectionIsCollapsed,
onMenuSelect: () => mf.insert("\\cancel{#@}"),
},
...mf.menuItems,
];
In this example, a new menu item for a Cancel command is added at the beginning of the menu.
The visible
handler checks that the selection is editable and not collapsed.
The onMenuSelect
handler replaces the selection with a \cancel{}
command.
The #@
token is replaced with the current selection, effectively wrapping
the selection in a \cancel{}
command.
To add a menu item at a specific position, use the findIndex()
method
to find the index of the menu item you want to insert relative to.
const isNonEmptySelection = () => mf.getValue(mf.selection).length > 0;
const getCancelArgument = () => {
const selection = mf.getValue(mf.selection);
// Is the selection a \cancel{...} command?
const match = selection.match(/^\\cancel{([^}]*)}$/);
return match ? match[1] : '';
};
const menuItems = mf.menuItems;
// Find the index of the "Cut" menu item
const index = menuItems.findIndex(item => item.id === 'cut');
mf.menuItems = [
// Add the new menu item before the "Cut" menu item
...menuItems.slice(0, index),
// Add the new commands
{ type: 'divider' },
{
label: "Cancel",
visible: () =>
mf.isSelectionEditable && isNonEmptySelection() && !getCancelArgument(),
onMenuSelect: () =>
mf.insert("\\cancel{#@}", { selectionMode: 'item' }),
},
{
label: "Uncancel",
visible: () => mf.isSelectionEditable && getCancelArgument(),
onMenuSelect: () =>
mf.insert(getCancelArgument(), { selectionMode: 'item' }),
},
{ type: 'divider' },
// Add the rest of the menu items after the "Cut" menu item
...menuItems.slice(index)
];
In this example, new menu items are added after the Cut menu item. We make a new array of menu items by slicing the original array into two parts:
- The first part is the menu items before the Cut item.
- The second part is the menu items after the Cut item. The new menu items are added in between the two parts.
We add a divider before and after the new menu items, which can be useful to group related menu items together.
We add two new menu items: Cancel and Uncancel. The Cancel item is only visible when the selection is editable, not empty and not already a cancel command. The Uncancel item is only visible when the selection is editable and is a cancel command. At most one of the two commands will be visible, allowing the user to either cancel or uncancel the selection.
When a menu item is selected, its onMenuSelect
handler is invoked and
a menu-select
custom event is dispatched.
It is generally simpler to provide a onMenuSelect
handler for each
menu item, but you can also listen to the menu-select
event to handle
all menu item selections in a single event handler.
The detail
property of the menu-select
event contains the following properties:
id
: The id of the menu item that was selected.label
: The label of the menu item that was selected.data
: The data payload associated with the menu item, if any.modifiers
: An object containing the state of the modifier keys when the menu item was selected. The following properties are defined:altKey
ctrlKey
metaKey
shiftKey
The example above which use onMenuSelect
can be rewritten to use the
menu-select
event instead. Note that in this case, the menu items have an
id
property, which is used to identify the menu item that was selected.
mf. menuItems = [
{
label: 'Copy',
id: 'copy'
},
{
label: 'Paste',
id: 'paste'
},
{
type: 'divider'
},
{
label: 'Submenu',
submenu: [
{
label: 'Submenu 1',
id: 'submenu-1'
},
{
label: 'Submenu 2',
id: 'submenu-2'
}
]
},
];
mf.addEventListener('menu-select', (event) =>
console.log('Menu item selected:', event.detail.id)
);
To hide the menu toggle button use the following CSS:
math-field::part(menu-toggle) {
display: none;
}
Even when the menu toggle button is hidden, the context menu is still accessible with a keyboard shortcut, right-click or long press.
To prevent the menu from being displayed, set the
mf.menuItems
property to an empty array:
mf.menuItems = [];
A Svelte wrapper manages the scaffolding of the web component, allowing it to be used like a standard web component with all attributes forwarded.
$ npm install --save-dev mathlive
<script lang="ts">
import "mathlive";
import type { MathfieldElement, MathfieldElementAttributes } from "mathlive";
import { on } from "svelte/events";
type Props = { value?: string } & Partial<MathfieldElementAttributes>;
let { value = $bindable(), ...rest }: Props = $props();
const init = (node: MathfieldElement) => {
$effect(() => {
if (value) node.value = value;
});
$effect(() => {
return on(node, "input", () => {
value = node.value;
});
});
};
</script>
<math-field use:init {...rest}></math-field>
Append the following to src/app.d.ts
. This provides autocomplete for the web component.
// ...previous code
import { type MathfieldElementAttributes } from "mathlive";
declare namespace svelteHTML {
interface IntrinsicElements {
'math-field': MathfieldElementAttributes;
}
}
<script>
import MathField from "$lib/MathField.svelte";
</script>
<MathField />
<script>
import MathField from "$lib/MathField.svelte";
let value = $state("1");
const config = {
"smart-mode": true
// ...
// see here for the full list of API's
// https://cortexjs.io/mathfield/api/
}
</script>
<!-- define settings via props -->
<MathField smart-mode="true" style="width:100%"></MathField>
<!-- define settings via an object -->
<MathField {...config}></MathField>
<!-- 2-way binding -->
<MathField bind:value></MathField>
<p>Current value: {value}</p>
<button
onclick={() => {value = String.raw`x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}`}}>
reset to default
</button>
date: Last Modified title: Keybindings and Inline Shortcuts slug: /mathfield/guides/shortcuts/ toc_max_heading_level: 2
A key binding is a combination of keys pressed simultaneously on a physical keyboard that triggers a command.
For example, pressing the Alt/Option/⌥ key and the V key at the same time will insert a square root. Pressing the Control/Command/⌘ key and the Z key at the same time will undo the last command.
There is an extensive set of default keybindings available.
To override, customize or add to the list of supported keybindings, set
the keybindings
property on a mathfield element.
const mf = document.getElementById('mf');
mf.keybindings = [
...mf.keybindings, // preserve existing keybindings
{
key: 'ctrl+alt+shift+[KeyT]',
ifMode: 'math',
command: ['switchMode', 'text'],
},
{
key: 'ctrl+alt+shift+[KeyT]',
ifMode: 'text',
command: ['switchMode', 'math'],
},
];
If using an insert
command, the LaTeX fragment argument of the function can include
one of the following special placeholder tokens:
#@
: replaced with the selection, if there is one. If there is no selection, replaced with an implicit argument to the left of the caret. For example, for12+34
, if the caret is at the end,#@
would be replaced with34
.#?
: replaced with a\placeholder{}
expression
Correctly handling keyboard shortcuts while accounting for non-US keyboard layout is surprisingly difficult. The mathfield element uses some heuristics that may occasionally result in surprising results.
This section details how keyboard events are used to determine which keyboard shortcut to activate.
Let's consider the keyboard shortcut CONTROL/⌘+ALT/OPTION+A
When this key combination is pressed on a keyboard with a US keyboard
layout, the event received will have the properties code = "KeyA"
and key = "\u00e5"
.
On a French AZERTY keyboard layout, the event received will have code = "KeyQ"
and key = "\u00e6"
.
Why is the code KeyQ
even though the user pressed the key labeled A
on their
AZERTY keyboard? On this keyboard layout, the Q and A keys are swapped compared
to the US layout and the code
property reflects the "physical" key pressed.
This is not unusual. While some keys retain their positions, many keys are swapped around or altogether unique in some layouts, particularly for punctuations and symbols. The code property of the event does not represent the label of the key, but indicates the physical position of the key as if it was on a US keyboard, in this case "the key immediately to the right of the caps lock key, which is labeled Q on a US keyboard (but is labeled A on a French keyboard)".
What we want to know is that the user pressed a key labeled A. But none of the information in the event record tells us that. The value of the key field varies depending on the keyboard layout and the modifiers pressed.
However, if we know the keyboard layout, we can use a table that maps the value of the key field to infer the label of the key the user pressed, i.e. what the user sees printed on the top of the key cap, regardless of its physical location on the keyboard. Once we have the label, we can figure out that the user pressed CONTROL/COMMAND/⌘ + A using the modifier fields of the event.
But how do we know what is the current keyboard layout? There is unfortunately no web platform API (broadly supported) to obtain that information. So one approach is to indicate programmatically which keyboard layout the user is using. Otherwise, the mathfield will use the user locale to guess the keyboard (for example, guessing to use the French AZERTY keyboard if the user locale is France).
Finally, the mathfield uses a heuristic to refine its guess: with each keyboard event, the mathfield checks that the info in the event record (specifically the code and key fields) is consistent with the current keyboard layout. If not, it finds a better matching keyboard layout, and will switch to that keyboard layout if it is confident enough of that guess.
The mathfield element currently has a limited set of "known" keyboard layouts. If you happen to use an unknown keyboard layout, it will guess the wrong keyboard layout. As a result some keyboard shortcuts may produce unexpected results.
An inline shortcut is a sequence of keystrokes typed on the keyboard that get replaced with another symbol. Unlike keybindings they cannot be used to trigger a command, only to insert a LaTeX fragment.
For example, typing the P key followed by the I key will
result in the \pi
\[ \pi \] LaTeX fragment being inserted, and not the pi
characters.
Inline shortcuts can be typed either using a physical keyboard or the virtual keyboard.
If a substitution was undesirable, use Undo (Control/Command/⌘ + Z) to revert to the raw input.
To prevent two consecutive characters to be recognized as part of a shortcut sequence, press the Space bar between them.
Some built-in inline shortcuts are defined, but they can be replaced or enhanced with additional shortcuts.
On line 4, we're adding a shortcut for "infty".
:::js
const mf = document.getElementById('mf');
mf.inlineShortcuts = {
...mf.inlineShortcuts, // Preserve default shortcuts
"infty": '\\infty'
};
:::html
<math-field id="mf">
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
To constraint the context in which a shortcut should apply, use the after
property:
mf.inlineShortcuts = {
...mf.inlineShortcuts, // Preserve default shortcuts
"in": {
after: "space | letter | digit | symbol | fence",
value: "\\in",
}
};
The after
property indicate in what context the shortcut should apply. One or
more values can be specified, separated by a |
sign. If any of the values
match, the shortcut will be applicable.
Possible values are:
"space"
A spacing command, such as\quad
"nothing"
The begining of a group"surd"
A square root or n-th root"frac"
A fraction"function"
A function such as\sin
orf
"letter"
A letter, such asx
orn
"digit"
0
through9
"binop"
A binary operator, such as+
"relop"
A relational operator, such as=
"punct"
A punctuation mark, such as,
"array"
An array, such as a matrix or cases statement"openfence"
An opening fence, such as(
"closefence"
A closing fence such as}
"text"
Some plain text
It may not be possible to define in advance all the keystroke combinations that should be interpreted as an inline shortcut.
For example, it might be desirable to recognize multi-character symbols, e.g. \( \mathrm{speed} = \frac{\mathrm{distance}}{\mathrm{time}} \)
There are several ways to represent multicharacter symbols in LaTeX.
Conventionally, the \mathit{}
command is used to represent variables and the
\mathrm{}
for function names. You may prefer to use \mathrm{}
in both cases.
The command \operatorname{}
may also be used for this purpose.
To recognize multicharacter symbols, provide a onInlineShortcut()
handler.
If the handler recognize the input as a valid multichar symbols, it
should return a command representing this symbols.
The string passed to the onInlineShortcut
handler is a raw sequence of
characters the user typed on the physical or virtual keyboard.
mf.onInlineShortcut = (_mf, s) => {
if (/^[A-Z][a-z]+$/.test(s)) return `\\mathrm{${s}}`;
if (/^[a-z][a-z]+$/.test(s)) return `\\mathit{${s}}`;
return '';
};
You can use the onInlineShortcut
handler to recognize arbitrary patterns.
For example:
mf.onInlineShortcut = (_mf, s) => {
if (/^[a-zA-Z][a-zA-Z0-9]*'?(_[a-zA-Z0-9]+'?)?$/.test(s)) {
const m = s.match(/^([a-zA-Z]+)([0-9]+)$/);
if (m) {
if (['alpha', 'beta', 'gamma'].includes(m[1]))
return `\\${m[1]}_{${m[2]}}`;
return `\\mathrm{${m[1]}}_{${m[2]}}`;
}
return `\\mathrm{${s}}`;
}
return '';
};
This will recognize "alpha34" -> \alpha_{34}
or "speed" -> \mathrm{speed}
.
To change how quickly a set of keys must be typed to be considered a shortcut
set the inlineShortcutTimeout
property.
It represents the maximum amount of time, in milliseconds, between consecutive characters for them to be considered part of the same shortcut sequence.
A value of 0 is the same as infinity: any consecutive character will be candidate for an inline shortcut, regardless of the interval between this character and the previous one.
A value of 750 will indicate that the maximum interval between two characters to be considered part of the same inline shortcut sequence is 3/4 of a second.
This is useful to enter +-
as a sequence of two characters, while also
supporting the ±
shortcut with the same sequence.
The first result can be entered by pausing slightly between the first and second character if this option is set to a value of 250 or so.
Note that some operations, such as clicking to change the selection, or losing the focus on the mathfield, will automatically timeout the shortcuts.
ASCIIMath defines a series of shortcuts that can be typed with ASCII characters to represent mathematical symbols and expressions.
**Learn more:** ASCIIMath and other default keybindingsLet's add an editable mathfield to a web page.
1. Load the Mathfield library from a CDN with a <script>
tag.
<script defer src="https://cdn.jsdelivr.net/npm/mathlive"></script>
Alternatively, you can use the unpkg CDN to load the module:
<script defer src="https://unpkg.com/mathlive"></script>
2. Add a <math-field>
tag. The content of this tag is the initial value
of the mathfield, as a LaTeX expression.
<math-field>f(x) = \sin(x+\pi)</math-field>
:::info[Note]
LaTeX is a plain text markup
language for structured documents. Most LaTeX commands start with a \
, for
example \sqrt
, \frac
and \sin
.
Read more about the LaTeX commands available in a mathfield :::
In the code playground below, change the content inside the <math-field>
tag.
For example change it to f(x) = \frac{x}{2}
.
:::info[Note]
The code playground here and in the rest of the documentation are live: when you modify the HTML or JavaScript code the output will update to reflect your changes.
Press Reset to bring back the playground to its original state.
:::
:::html
<math-field>
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
Here's a complete web page using a <math-field>
in vanilla HTML:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>untitled</title>
<script defer src="https://cdn.jsdelivr.net/npm/mathlive"></script>
</head>
<body>
<math-field id="mf">x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}</math-field>
<script>
mf.addEventListener('input', evt =>
console.log('Value:', evt.target.value)
);
</script>
</body>
</html>
To use mathfields in a React project, use a <math-field>
tag with JSX:
import "https://esm.run/mathlive";
import { useState } from "react";
export View = () => {
const [value, setValue] = useState("f(x) = \\frac{x}{2}");
return (
<math-field
onInput={evt => setValue(evt.target.value)}
> {value} </math-field>
<p>Value: {value}</p>
);
}
:::warning[Caution: HTML quirks mode]
The HTML quirks mode is not supported.
The host page must use the strict mode by including a <!DOCTYPE html>
directive at the top of the page.
Without it, the layout of the expression inside the mathfield may be incorrect.
:::
:::warning[Caution: file://
protocol]
For security reasons there are some restrictions when using the file://
protocol. This happens if you open a file in the browser from your local file
storage. You will notice the adress in the browser address bar starts with file://
.
In this situation, some functionality may not be available and some errors may be displayed in the console.
To prevent this, use a local file server.
With VSCode, the Live Server extension can be used to launch a local development server with one click.
:::
:::warning[Caution: CSP (Content Security Policy)]
In order to interactively display mathfields, some CSS styles are generated dynamically. If you are using a Content Security Policy (CSP), you may need to adjust it to allow the use of inline styles.
Specifically, you may need to add 'unsafe-inline'
to the style-src
directive in your CSP.
<meta http-equiv="Content-Security-Policy" content="style-src 'self' 'unsafe-inline';">
:::
Learn more about other options to add mathfields to your projectdate: Last Modified title: Commands slug: /mathfield/guides/commands/
You can perform editing operations on the mathfield programmatically. For example, to insert a fraction when the user clicks a button.
You can do this by dispatching commands to the mathfield, such as
"select-all"
, "move-to-next-char"
, "delete-backward"
, etc...
To dispatch commands use the mf.executeCommand()
method.
mf.executeCommand("delete-backward");
To associate commands with virtual keyboard keycaps use the command
property of the keycap definition. For example:
{
"class": "action",
"label": "Delete",
"command": 'perform-with-feedback("delete-backward")'
}
Commands are identified by a string called the selector.
The selector can use either CamelCase or kebab-case syntax. For example:
"moveToNextChar"
or "move-to-next-char"
are the same selector.
Most commands take no parameters. When a command does have a parameter, a tuple
with the selector and the commands arguments can be passed to
executeCommand()
. For example:
mf.executeCommand(["insert", "(#0)"]);
The command above will insert an open and close parenthesis around the selection (the #0
sequence is replaced with the current selection).
insert
This selector takes two arguments. The first one is required and is the content to be inserted, as a string. The second one is an optional set of key value pairs:insertionMode
: one of"replaceSelection"
,"replaceAll"
,"insertBefore"
or"insertAfter"
.selectionMode
: one of"placeholder"
(the selection will be the first available placeholder in the item that has been inserted),"after"
(the selection will be an insertion point after the item that has been inserted),"before"
(the selection will be an insertion point before the item that has been inserted) or"item"
(the item that was inserted will be selected).
delete
Synonym fordeleteNextChar
deleteBackward
deleteForward
deleteNextWord
deletePreviousWord
deleteToGroupStart
deleteToGroupEnd
deleteToMathFieldEnd
deleteAll
transpose
undo
redo
cutToClipboard
copyToClipboard
pasteFromClipboard
commit
The user has completed input. Triggered when pressing the RETURN or ENTER key.switchMode
complete
Exit command mode and insert resultnextSuggestion
andpreviousSuggestion
when the popover panel is selected, display the next/previous suggestiontoggleKeystrokeCaption
Show/hide the keystroke caption panel. This panel displays the keys being typed, including the shortcuts. Great for demos!toggleVirtualKeyboard
Show/hide the virtual keyboard
scrollToStart
scrollToEnd
scrollIntoView
moveToNextChar
moveToPreviousChar
moveToNextPlaceholder
moveToPreviousPlaceholder
moveToNextWord
moveToPreviousWord
moveToGroupStart
moveToGroupEnd
moveToMathfieldStart
moveToMathfieldEnd
moveUp
moveDown
moveToSuperscript
moveToSubscript
moveToOpposite
moveBeforeParent
moveAfterParent
selectGroup
selectAll
extendToNextChar
extendToPreviousChar
extendToNextWord
extendToPreviousWord
extendUp
extendDown
extendToNextBoundary
extendToPreviousBoundary
extendToGroupStart
extendToGroupEnd
extendToMathFieldStart
extendToMathFieldEnd
addRowAfter
addRowBefore
addColumnAfter
addColumnBefore
removeRow
removeColumn
-
speak
This selector takes an optional argument, the string that determines what should be spoken. The valid values are:all
left
right
selection
parent
group
The second parameter determines whether what is being spoken should be highlighted. It is an object:
{withHighlighting: boolean}
(default is false). Note: highlighting currently only works when using Amazon's AWS speech synthesizer.
To change the value of a <math-field>
element programatically set its value
property.
In the playground below, the LaTeX input field is editable and is reflected in the mathfield, and vice-versa.
:::info[Note]
Note that we use the silenceNotifications
option when
changing the content of the mathfield, to prevent an "input"
event from being
triggered and creating an infinite loop.
:::
:::js
const mf = document.getElementById("formula");
const latex = document.getElementById("latex");
//
mf.addEventListener("input",(ev) => latex.value = mf.value);
//
latex.value = mf.value;
//
// Listen for changes in the "latex" text field,
// and reflect its value in the mathfield.
//
latex.addEventListener("input", (ev) =>
mf.setValue(
ev.target.value,
{silenceNotifications: true}
)
);
:::html
<label>Mathfield</label>
<math-field id="formula">
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
<label>Latex</label>
<textarea id="latex" autocapitalize="off" autocomplete="off"
autocorrect="off" spellcheck="false"></textarea>
To read the content of a <math-field>
element as a LaTeX string use its value
property,
just like with a <textarea>
.
To be notified when the content of the mathfield is modified listen for
an "input"
event.
Try: modify the "input"
event below to a "change"
event. Notice how the "change"
event
is only sent if you press the RETURN or ENTER key, or when the mathfield
loses focus and the content has been modified.
:::js
document.getElementById('formula').addEventListener('input',(ev) => {
// `ev.target` is an instance of `MathfieldElement`
console.log(ev.target.value);
});
:::html
<math-field id="formula">
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
Reading the value
property is equivalent to calling the getValue()
method with
no argument.
To control the format of the result, pass options to getValue()
.
For example to get the content as a MathJSON expression, use mf.getValue('math-json')
.
Try: Other formats are available: change "math-json"
to "spoken-text"
.
:::html
<math-field id="formula">
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
:::js
import 'compute-engine';
const mf = document.getElementById('formula');
// `ev.target` is an instance of `MathfieldElement`
mf.addEventListener('input',
(ev) => console.log(ev.target.getValue('math-json'))
);
The MathJSON format is a lightweight mathematical notation interchange format.
The Compute Engine is a JavaScript library that can perform mathematical operations on MathJSON expressions.
To use the Compute Engine, import the Compute Engine library, e.g. import "https://esm.run/@cortex-js/compute-engine"
If the Compute Engine has been loaded in the page, mathfields will automatically create an instance of the compute engine when needed.
To access that shared Compute Engine instance, use MathfieldElement.computeEngine
.
:::info[Note]
If the value returned is undefined
, it means that the Compute Engine has not
been loaded in the page.
:::
You can also create your own instance of the Compute Engine and pass it to the
mathfield using the computeEngine
property.
import { ComputeEngine } from 'compute-engine';
MathfieldElement.computeEngine = new ComputeEngine();
:::info[Note] This is usually not necessary and you can rely on the default shared instance of the Compute Engine. :::
To read the content of a <math-field>
element as a boxed MathJSON expression use the mathfield expression
property.
Using mf.expression
is equivalent to calling MathfieldElement.computeEngine.parse(mf.value)
or MathfieldElement.computeEngine.box(mf.getValue("math-json"))
.
Once you have a boxed expression, you can perform operations on it using the Compute Engine.
For example, you can:
- evaluate it using
mf.expression.evaluate()
- simplify it using
mf.expression.simplify()
- compare it to another expression using
mf.expression.isEqual()
andmf.expression.isSame()
- compile it to JavaScript
:::info[Note]
Note that the expressions are returned by default in a canonical form, which means that
they may be different from the original input. For example, x + 1
and 1 + x
are considered equal, and will be returned as 1 + x
. If necessary you
can request non-canonical forms.
:::
You can also extend the definitions of the Compute Engine by adding your own.
:::html
<math-field id="formula">
\mathrm{Expand}((a+b)^6)
</math-field>
:::js
import 'compute-engine';
const mf = document.getElementById('formula');
mf.addEventListener('input', () =>
console.log(mf.expression.evaluate())
);
console.log(mf.expression.evaluate());
The mathfield element dispatches the beforeinput
and input
Input Events, which are also
implemented by <textarea>
and similar elements.
The beforeinput
and input
events implement the InputEvent
interface.
These events are sent before (beforeinput
event) and after (input
event) a
user attempts to edit the mathfield. This includes insertion and deletion of
content, and formatting changes.
The events include an inputType
property that describe what caused the event
to be dispatched.
inputType |
|
---|---|
insertText |
Some content was added. It could be math content, plain text or raw latex. It could also be a row or column in matrix that was added. |
insertLineBreak |
The RETURN or ENTER key was pressed. Note that the actual content of the mathfield may not have changed. |
insertFromPaste |
The content of the mathfield was changed because of a paste operation |
deleteWordBackward |
|
deleteWordForward |
|
deleteWordForward |
|
deleteSoftLineBackward |
|
deleteSoftLineForward |
|
deleteHardLineBackward |
|
deleteHardLineForward |
|
deleteByCut |
The content was changed because of a cut operation |
deleteContent |
Some content was deleted, but no particular direction applied |
deleteContentBackward |
|
deleteContentForward |
|
historyUndo |
The content was changed because of an undo command |
historyRedo |
The content was changed because of a redo command |
:::warning
On iOS, the inputType
property is removed. However, its content can also be access as ev.data
. Until this issue is addressed in iOS, for better compatibility, use ev.data
.
:::
The beforeinput
event is dispatched before any modifications to the mathfield
have been done. This event is cancelable. Calling preventDefault()
on the
event will cause the modification to be prevented.
If the beforeinput
event is not canceled, the mathfield content is modified
and a input
event is dispatched. The input
event is not cancelable.
To detect when the user presses the RETURN or ENTER key in a mathfield,
listen for the change
event.
Note that this event is not fired when in LaTeX editing mode, where Return or Enter is used to exit the mode.
This event is also fired if the mathfield loses focus, even if the user did not
use the keyboard. This behavior matches the <textarea>
element.
To listen specifically for a press of the RETURN or ENTER key on the
keyboard listen for an input
event with an inputType
(or ev.data
on iOS) property of "insertLineBreak"
.
mf.addEventListener('beforeinput', (ev) => {
if (ev.inputType === 'insertLineBreak') {
mf.executeCommand("moveToNextPlaceholder");
ev.preventDefault();
};
});
In most cases MathLive will respond to mouse and keyboard interactions with the mathfield. However, in some cases it might be useful to detect when a mathfield is clicked on. For example, you could display one or more read-only mathfields in a list and prompt the user to pick one by clicking on it.
In general, to be notified of an event, use mf.addEventListener()
. This
includes some generic events, as well as some that are specific to mathfields.
Events that target a DOM element inside the mathfield (inside the shadow DOM)
will bubble and be retargeted to appear as if they had targeted the
mathfield (that is, the evt.target
will be the mathfield itself).
This include the following standard events:
change
: the RETURN or ENTER key was pressed, or the field lost focus.blur
,focus
,focusin
,focusout
click
mousedown
,mouseup
,mousemove
,mouseout,
mouseover`beforeinput
,input
. If theinputType
property of the event is"insertLineBreak"
the RETURN or ENTER key was pressedkeydown
,keypress
,keyup
wheel
- all the pointer events such as
pointerdown
,pointerup
, etc... and all the touch events
As well as these mathfield specific events:
mount
: the mathfield has been connected to the DOMunmount
: the mathfield is no longer connected to the DOMfocus-out
: tab key interactionsmove-out
: arrow key interactionsmode-change
: change tomath
,text
orlatex
moderead-aloud-status-change
selection-change
undo-state-change
A user may navigate outside of a mathfield by pressing the arrow keys, or the tab, home and end keys.
By default, the mathfield reacts as a standard textarea field: moving to the next focusable element when the TAB (or SHIFT+TAB) key is pressed, and doing nothing when reaching the start or end of the mathfield when navigation with the arrow keys.
In some cases, you may want to implement a different behavior. For example if a mathfield is embedded inside an editable paragraph, you may want the arrow keys to exit the mathfield when reaching the end/start. Or you may want the TAB key to simply move the caret to the end/start of the mathfield.
To change the behavior of a mathfield when navigation out of a mathfield listen
for the focus-out
and move-out
events.
The detail
property of those events indicate the direction of navigation.
To cancel the default behavior, use ev.preventDefault()
.
mf.addEventListener('move-out', (ev) => {
ev.preventDefault();
// Remove focus from mathfield
mf.blur();
// Focus some other element, use ev.detail.direction to detect if
// navigating backward, forward, upward or downward
// ...
});
mf.addEventListener('focus-out', (ev) => {
ev.preventDefault();
// Move the cursor to the start/end of the mathfield on tab
if (ev.detail.direction === 'forward')
mf.executeCommand('moveToMathfieldEnd');
else if (ev.detail.direction === 'backward')
mf.executeCommand('moveToMathfieldStart');
});
Users can export the content of the mathfield by using standard Copy/Cut commands (Control/⌘ X and Control/⌘ C).
Multiple flavors are put on the clipboard:
text/plain |
LaTeX wrapped with a $$ . |
application/x-latex |
Raw LaTeX |
application/json |
A MathJSON representation of the formula. |
The recipient of the Paste operation can pick whichever is most appropriate.
If the recipient is a web app, the specific flavor can be accessed using
the event.clipboardData.getData()
API. If the recipient is a native app,
the most popular browsers currently only make accessible the text flavor,
with a LaTeX representation of the formula.
The LaTeX in the text/plain
flavor is "wrapped" to make it easier for the
recipient of the paste to recognize that this content is in LaTeX format.
:::info[Note]
For improved interoperability, the exported LaTeX uses the latex-expanded
format. In this format, any macros in the formula are expanded to their
definition. For example, the \differentialD
command is exported as its
corresponding definition, \mathrm{d}
.
:::
To customize the content of the text/plain
flavor, use the onExport()
hook.
For example, to wrap the exported latex with <math>...</math>
instead:
mf.onExport = (mf, latex) => `<math>${latex}</math>`
To export the "raw" (not expanded) LaTeX), use:
mf.onExport = (mf, latex, range) => `$$${mf.getValue(range, 'latex')}$$`
The exported format doesn't have to be LaTeX. To export ASCIIMath instead:
mf.onExport = (mf, latex, range) =>
"`" + mf.getValue(range, 'ascii-math') + "`"
:::info[Note]
The standard delimiter for ASCIIMath is the ` (backtick) character
:::
The text color ("ink") and background color ("paper"), as well as other
stylistic attributes, can be changed on a mathfield, or a portion of a mathfield
using applyStyle()
.
:::info[Note] This style applies to the content of the formula and will be reflected in the LaTeX output. To change the appearance of the mathfield but not the content of the formula, see Customizing. :::
:::js
const mf = document.getElementById('formula');
// Change the background color of the entire mathfield
mf.applyStyle(
{ backgroundColor: 'yellow' },
{ range: [0, -1] }
);
:::html
<math-field id="formula">
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
To change the style of a portion of the mathfield, specify a selection range
to applyStyle()
.
:::js
const mf = document.getElementById('formula');
// Change the color and size of the first two characters of the mathfield
mf.applyStyle({color: "red", fontSize: 7 }, { range: [0, 2] });
:::html
<math-field id="formula">
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
To remove a style, set the value of the fontFamily
, color
or backgroundColor
property to "none"
, or the value of the fontShape
, fontSeries
or fontSize
property to "auto"
.
:::info[Note]
You can ignore styles applied to a formula by using mf.getValue('latex-unstyled')
:::
import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem';
The **Mathfield virtual keyboard** is a keyboard displayed on screen that gives access to specialized symbols for math input with only a tap.This guide explains how to customize the virtual keyboard.
Learn more about **using the math virtual keyboard**The default behavior is to display the virtual keyboard when a mathfield is focused on a touch-enabled devices: mobile phones, tablets and laptops with a touch-screen.
This behavior can be changed with the mf.mathVirtualKeyboardPolicy
property
or the equivalent math-virtual-keyboard-policy
attribute (set one or the
other, not both).
mathVirtualKeyboardPolicy |
|
---|---|
"auto" |
On touch-enabled devices, show the virtual keyboard panel when the mathfield is focused. This is the default behavior. |
"manual" |
Do not show the virtual keyboard panel automatically. The visibility of the virtual keyboard panel can be controlled programatically with mathVirtualKeyboard.show() and mathVirtualKeyboard.hide() |
"sandboxed" |
The virtual keyboard is displayed in the current browsing context (iframe) if it has a defined container or is the top-level browsing context. |
To show the math virtual keyboard anytime the mathfield is focused, on touch or non-touch devices, use:
mf.mathVirtualKeyboardPolicy = "manual";
mf.addEventListener("focusin", () => mathVirtualKeyboard.show());
mf.addEventListener("focusout", () => mathVirtualKeyboard.hide());
The virtual keyboard toggle is displayed by default when the mathfield can be modified, that is when it's not read-only or disabled.
To control the visibility of the virtual keyboard toggle, use CSS.
For example to hide the toggle unless on a touch-enabled device, use:
@media not (pointer: coarse) {
math-field::part(virtual-keyboard-toggle) {
display: none;
}
}
The virtual keyboard panel displays multiple layouts which can be
toggled using the layout switcher: numeric
, symbols
, alphabetic
and greek
.
To choose which layouts are listed in the layout switcher, use the
mathVirtualKeyboard.layouts
property.
For example, to only show the numeric and symbols layouts, use:
:::html
<math-field>x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}</math-field>
:::js
document.querySelector('math-field').
addEventListener('focus', () => {
mathVirtualKeyboard.layouts = ["numeric", "symbols"];
mathVirtualKeyboard.visible = true;
});
To revert to the default layouts, use:
mathVirtualKeyboard.layouts = "default";
There is a single instance of the virtual keyboard panel, shared by all mathfields. The layouts are shared by all mathfields as well.
To display a different set of layouts for a specific mathfield, change the
mathVirtualKeyboardLayouts
property of the mathfield when it is focused.
// Layout for mathfield mf1
mf1.addEventListener("focusin", () => {
mathVirtualKeyboard.layouts = ["numeric", "symbols"];
});
// Layout for mathfield mf2
mf2.addEventListener("focusin", () => {
mathVirtualKeyboard.layouts = ["minimalist"];
});
In addition to numeric
, symbols
, alphabetic
and greek
, the
following layouts are available:
The "minimalist"
layout is focused on entry of simple expressions.
mathVirtualKeyboard.layouts = ["minimalist"];
The "compact"
layout is similar to "minimalist"
but the keycaps include variants.
mathVirtualKeyboard.layouts = ["compact"];
The "numeric-only"
layout is suitable for input that is purely numeric.
mathVirtualKeyboard.layouts = ["numeric-only"];
In addition to the built-in layouts, you can define your own layouts.
The simplest way to define a custom layout is to set mathVirtualKeyboard.layouts
to an object
literal with a rows
property, an array of keycaps.
For best result, you should make sure the rows have no more than 10 keycaps.
:::html
<math-field>x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}</math-field>
:::js
document.querySelector('math-field').
addEventListener('focus', () => {
mathVirtualKeyboard.layouts = {
rows: [
[
"+", "-", "\\times", "\\frac{#@}{#?}", "=", ".",
"(", ")", "\\sqrt{#0}", "#@^{#?}",
],
["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"],
]
};
mathVirtualKeyboard.visible = true;
});
Each keycap is a LaTeX string which is used both as the label of the keycap, and as the content inserted when the keycap is pressed.
You'll notice from the example above that the LaTeX fragments defining the keycap can contain some special placeholder tokens:
Token | |
---|---|
#@ |
Replaced with the selection, if there is one. If there is no selection, replaced with an implicit argument to the left of the caret. For example, for 12+34 , if the caret is at the end, #@ would be replaced with 34 . |
#0 |
Replaced with the selection if there is one, a \placeholder{} command otherwise |
#? |
Replaced with a \placeholder{} command |
The value of the keycap can be a LaTeX string, or one of the special values below, corresponding to a standard keycap. These shortcuts define the label, appearance, command when pressed, shifted command and variants for those keys.
"[left]"
"[right]"
"[return]"
"[hide-keyboard]"
"[shift]"
"[backspace]"
"[undo]"
"[redo]"
"[cut]"
"[copy]"
"[paste]"
"[.]"
"[+]"
"[-]"
"[/]"
"[*]"
"[=]"
"[(]"
"[)]"
"[0]"
"[1]"
"[2]"
"[3]"
"[4]"
"[5]"
"[6]"
"[7]"
"[8]"
"[9]"
"[separator]"
["hr"]
"[foreground-color]"
"[background-color]"
For more control over the appearance and behavior of a keycap use an object literal with the following properties:
label
: the label of the keycap, displayed using the system font. This can include some HTML markup, for example"<span><i>x</i> ²</span>"
. If property is absent, thelatex
property is used for the label of the keycap. The label can also be one of the keycap shortcuts mentioned above, e.g.[left]
. If a keycap shortcut is used, the other properties override the values defined by the shortcut.latex
: if nolabel
is provided, the value of thelatex
property is used as the label of the keycap. This property is also used to insert content in the mathfield when the keycap is pressed.key
: if present, when the keycap is pressed the corresponding physical keyboard key is simulated, potentially triggering keyboard shortcuts.insert
: if present, a LaTeX string to be inserted when the keycap is pressed.command
: the command to perform when the keycap is pressed. For example:["performWithFeedback", "commit"]
.class
: a set of CSS classes to style this keycap. The classes can be custom defined (see below about thestyle
layer property), or be one or more of the standard ones:tex
: use the TeX font for its label. Using thetex
class is not necessary if using thelatex
property to define the label.ghost
: the keycap with no border or backgroundsmall
: display the label in a smaller sizeaction
: an "action" keycap (for arrows, return, etc...)bottom
,left
,right
: alignment of the labelhide-shift
: do not display the shift top-right label on the keycap if ashift
property is provided.
width
: the width of the keycap, as a multiple of a standard keycap. That is, 0.5 for half-wide keys, 1.5 for one and half wide keys, etc...aside
: an optional small label displayed below the keycap. This label may not be displayed if the space available is too small.shift
: a LaTeX string or a keycap record indicating what happens when this keycap is pressed with the SHIFT key down.variants
: an array of keycaps (either as string or keycap records) defining the variants for this keycap (see below).
If neither insert
nor command
are provided, the latex
or key
properties
are used to define the content inserted when the keycap is pressed.
Here's an example of a basic keyboard layout:
mathVirtualKeyboard.layouts = {
label: 'Basic',
rows: [
[
'[7]', '[8]', '[9]', '[+]',
{ label: '[separator]', width: 0.5 },
{ class: 'small', latex: '\\frac{#@}{#0}' },
'\\varnothing', '\\infty', '\\in', '\\notin',
'[separator]',
],
[
'[4]', '[5]', '[6]', '[-]',
{ label: '[separator]', width: 0.5 },
'[(]', '[)]', '\\lt', '\\le', '\\hat{=}', '[separator]',
],
[
'[1]', '[2]', '[3]', '\\cdot',
{ label: '[separator]', width: 0.5 },
'[', ']', '\\gt', '\\ge',
{ label: '[backspace]', width: 2 },
],
[
{ label: '[0]', width: 2 }, '[.]', '\\colon',
{ label: '[separator]', width: 0.5 },
'\\lbrace', '\\rbrace', '=', '\\ne', '[left]', '[right]',
],
],
};
The default layouts include variants for many of their keycaps. These variants are accessed with a long press on the keycap. The variants are typically related, but less frequently used version of the main keycap.
You can define variants for a custom layout by specifying a variants
property with the definition of a keycap. The value of the variants
property
is an array of VirtualKeyboardKeycap
. As a shortcut, a string can also be
used, which is equivalent to a VirtualKeyboardKeycap
with a latex
property
equal to the string, that is, it will display the latex string as the keycap
label and insert it when the key is pressed.
rows: [
[
{ latex: "a", variants: ["A", "\\alpha", "\\Alpha"] }
...
]
]
If you want to apply custom CSS classes to some keycaps, you can provide
a definition for them using the style
property. Note that in that case
you can't use the rows
shortcut, you must provide the full definition
of the layers.
mathVirtualKeyboard.layouts = [
{
label: "minimal",
tooltip: "Only the essential",
layers: [
{
style: ".digit { background: blue; color: white }",
rows: [
[
'+',
'-',
'\\times',
'\\frac{#@}{#?}',
'=',
'.',
'(',
')',
'\\sqrt{#0}',
'#@^{#?}',
],
[
{ class: 'digit', latex: '1' },
{ class: 'digit', latex: '2' },
{ class: 'digit', latex: '3' },
{ class: 'digit', latex: '4' },
{ class: 'digit', latex: '5' },
{ class: 'digit', latex: '6' },
{ class: 'digit', latex: '7' },
{ class: 'digit', latex: '8' },
{ class: 'digit', latex: '9' },
{ class: 'digit', latex: '0' },
],
],
},
],
},
"alphabetic",
];
Most keyboard layouts are made of a single layer. However, if your layout
includes multiple layers, use the layers
property to provide an array of
layers.
mathVirtualKeyboard.layouts = {
layers: [
{
rows: [
[
"+", "-", "\\times", "\\frac{#@}{#?}", "=", ".",
"(", ")", "\\sqrt{#0}", "#@^{#?}",
],
]
},
{
rows: [
["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"],
]
}
],
};
You can also mix default layouts with your own. For example, to add the alphabetic layout after your own:
mathVirtualKeyboard.layouts = [
{
label: "minimal",
tooltip: "Only the essential",
rows: [
[
"+", "-", "\\times", "\\frac{#@}{#?}", "=", ".",
"(", ")", "\\sqrt{#0}", "#@^{#?}",
],
["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"],
]
},
"alphabetic"
];
If you include more than one layout, it's a good idea to provide a label and tooltip so they get propertly displayed in the layout switcher.
To customize the appearance of the virtual keyboard panel set the following
CSS variables on a selector that applies to the container of the virtual
keyboard panel, which is the <body>
element by default:
body {
--keyboard-zindex: 3000;
}
You can also set these CSS variables programmatically:
document.body.style.setProperty("--keyboard-zindex", "3000");
To specify the stack order of the virtual keyboard relative to
other DOM elements set the --keyboard-zindex
CSS variable.
The default zindex
of the virtual keyboard is 105
.
To control the appearance of the virtual keyboard text and background colors, set the value of the following CSS variables to a CSS color:
-
--keyboard-accent-color
-
--keyboard-toolbar-text
-
--keyboard-toolbar-text-active
-
--keyboard-toolbar-background
-
--keyboard-toolbar-background-hover
-
--keyboard-toolbar-background-selected
-
--keycap-background
-
--keycap-background-hover
-
--keycap-background-active
-
--keycap-background-pressed
-
--keycap-border
-
--keycap-border-bottom
-
--keycap-text
-
--keycap-text-active
-
--keycap-text-hover
-
--keycap-text-pressed
-
--keycap-shift-text
-
--keycap-shift-color
-
--keycap-primary-background
-
--keycap-primary-text
-
--keycap-primary-background-hover
-
--keycap-secondary-background
-
--keycap-secondary-background-hover
-
--keycap-secondary-text
-
--keycap-secondary-border
-
--keycap-secondary-border-bottom
-
--box-placeholder-color
-
--variant-panel-background
-
--variant-keycap-text
-
--variant-keycap-text-active
-
--variant-keycap-background-active
The following CSS variables are a border shorthand value:
--keyboard-border
--keyboard-horizontal-rule
By default the virtual keyboard is sized so that it can be used comfortably on touch-devices. Its size will adjust based on the available space in its container, which is the viewport by default.
However, you may want to have a more compact virtual keyboard to leave more
room for the content. You can control the appearance of the virtual keyboard
using some CSS variables. Set those variables in a rule that applies to
the entire document, for example the body
element selector.
body {
--keycap-height: 24px;
--keycap-font-size: 16px;
--keycap-shift-font-size: 9px;
--keycap-small-font-size: 9px;
--keycap-extra-small-font-size: 9px;
--keyboard-toolbar-font-size: 16px;
--keycap-gap: 1px;
}
The following CSS variables can be used to adjust the layout:
-
--keycap-height
-
--keycap-max-width
-
--keycap-gap
-
--keycap-font-size
-
--keycap-shift-font-size
-
--keycap-small-font-size
-
--keycap-extra-small-font-size
-
--keycap-secondary-border-bottom
-
--keycap-secondary-border-bottom
-
--keyboard-toolbar-font-size
-
--keyboard-padding-horizontal
-
--keyboard-padding-top
-
--keyboard-padding-bottom
-
--keyboard-row-padding-left
-
--keyboard-row-padding-right
-
--variant-keycap-length
-
--variant-keycap-font-size
-
--variant-keycap-aside-font-size
To require the virtual keyboard to be used for input and ignore
keys pressed on the physical keyboard listen and preventDefault()
on "keydown"
events during the capture phase, and show the virtual keyboard when the mathfield
is focused.
mf.addEventListener("keydown", (evt) =>
evt.preventDefault(), { capture: true });
mf.addEventListener("focus", () =>
mathVirtualKeyboard.show());
By default the virtual keyboard is inserted at the end of the document's body
element.
In some cases you may want to display the virtual keyboard in some other container.
For example when using full screen elements that contain a mathfield, you want to make sure the virtual keyboard panel is visible by attaching it to the full screen element.
To select which DOM element the virtual keyboard is attached to, set the
mathVirtualKeyboard.container
property to the desired DOM element.
:::warning
The container element should be at least 320px wide to ensure that the default layouts can fit. The height of the container element will be adjusted so that the virtual keyboard can fit.
:::
The virtual keyboard panel is positioned relative to the container element
using the position: absolute
CSS property. This means that the virtual
keyboard panel will not affect the layout of the container element.
However, the container element may need to adjust its layout to make room for the virtual keyboard panel. For example, if the container element is a full screen element, it may need to adjust its height to make room for the virtual keyboard panel.
To react to the geometry changes of the virtual keyboard panel, listen
to the "geometrychange"
event on the mathVirtualKeyboard
object.
The bounding rectangle of the virtual keyboard is available in the
mathVirtualKeyboard.boundingRect
property.
For example, to adjust the height of the container element to make room for the virtual keyboard panel:
mathVirtualKeyboard.addEventListener("geometrychange", () => {
container.style.height =
mathVirtualKeyboard.boundingRect.height + "px";
});
By default the "alphabetic"
layout is determined based on the locale (QWERTY
for english speaking countries, AZERTY for french speaking
countries, etc..).
To select a different alphabetic layout, such as DVORAK or COLEMAK,
use the mathVirtualKeyboard.alphabeticLayout
property.
:::js
const mf = document.querySelector('math-field');
document.querySelector('math-field').addEventListener('focus', () => {
mathVirtualKeyboard.layouts = ["alphabetic"];
mathVirtualKeyboard.alphabeticLayout = "dvorak";
mathVirtualKeyboard.visible = true;
});
:::html
<math-field>
x=\frac{-b\pm \sqrt{b^2-4ac}}{2a}
</math-field>
In this tutorial, we'll create a web-based quiz application that allows students to practice simplifying mathematical expressions into polynomials.
We'll use two powerful tools: MathLive for math input and Compute Engine for evaluating mathematical expressions.
In this tutorial, we'll use HTML and JavaScript.
Let's start by setting up our HTML file.
<!doctype html>
<html>
<head>
<title>Math Quiz</title>
</head>
<body>
<!-- Interactive elements will be added here -->
</body>
<script type="module">
// Import the Mathfield and Compute Engine libraries
import "https://esm.run/mathlive";
import "https://esm.run/@cortex-js/compute-engine";
// JavaScript code will be added here
</script>
</html>
For convenience, we're loading the MathLive and ComputeEngine library from the jsdelivr CDN. You can also download the libraries and host them locally.
Since we want to use the Compute Engine, we'll need to load its library as well. We could use MathLive without the Compute Engine, but we'll need it to evaluate the student's input.
:::warning
Note that the <script>
tag has a type="module"
attribute. This is required
to use the import
statement.
:::
Our quiz will have a simple interface: a question area, an input field for the answer, a submission button, and a feedback section.
<p>Simplify the expression: (x+1)(2x -1)</p>
<math-field id="answer"></math-field>
<button id="submitAnswer">Check Answer</button>
<div id="feedback"></div>
When the MathLive library is loaded, a new HTML element becomes available:
<math-field>
.
This element is a math input field that allows users to type math expressions.
We'll use this element to allow students to input their answers.
Let's add some CSS to make our quiz look nicer.
<style>
math-field {
width: 100%;
border-radius: 8px;
margin: 8px 0;
}
button {
border-radius: 8px;
padding: 8px;
margin: 8px 0;
font-size: 1em;
font-weight: bold;
font-family: system-ui;
}
p {
font-family: system-ui;
font-size: 1.5em;
padding: 8px;
}
#feedback {
font-family: system-ui;
font-size: 1.2em;
font-weight: bold;
display: flex;
justify-content: center;
padding: 8px;
border: 1px solid #ddd;
border-radius: 8px;
background: #f0f0f0;
}
</style>
Now, let's add functionality to process the student's input and compare it with the expected answer.
const expectedAnswer = "2x^2+x-1";
function checkAnswer() {
const studentInput = mathfield.value;
// Compare the expressions as strings
const feedback = studentInput === expectedAnswer ?
'Correct! 😃' : 'Try again. 😞';
document.getElementById('feedback').textContent = feedback;
}
const answerButton = document.getElementById('submitAnswer');
answerButton.addEventListener('click', checkAnswer);
To read the content of the math input field, we use the value
property of the <math-field>
element. This property returns a LaTeX string representation of
the math expression
We then compare the student's input with the expected answer. If the student's input matches the expected answer, we'll display a "Correct!" message. Otherwise, we'll display a "Try again." message.
While comparing the student's input with the expected answer works, it's not very flexible. For example, if we want to accept equivalent answers, we'll have to manually check for each possible equivalent answer. This can be tedious and error-prone.
Instead, we can use the Compute Engine to evaluate the student's input and compare it with the expected answer. This way, we can accept equivalent answers without having to manually check for each one.
When the Compute Engine library is loaded in the page, the MathLive library automatically uses it to evaluate the math expressions entered in the math input field.
The Compute Engine represents mathematical expressions as a MathJSON data structure. This is a more flexible representation than LaTeX, and allows us to compare expressions in a more robust way.
To get the MathJSON representation of the student's input, we can use the expression
property of the <math-field>
element.
We can get a reference to the Compute Engine instance used by MathLive by accessing the computeEngine
property of MathfieldElement
. We can then use the parse()
method to convert the expected answer into a MathJSON expression.
We'll modify our checkAnswer()
function as follows:
const ce = MathfieldElement.computeEngine;
const expectedAnswer = ce.parse("2x^2+x-1");
function checkAnswer() {
const studentInput = mathfield.expression;
// Compare the expressions using `isSame()`
const feedback = studentInput.isSame(expectedAnswer) ?
'Correct! 😃' : 'Try again. 😞';
document.getElementById('feedback').textContent = feedback;
}
The method ce.parse()
returns a boxed expression from a LaTeX string. A
boxed expression is a JavaScript object that represents a mathematical
expression.
The Compute Engine provides many operations that can be performed on boxed expressions, including calculus, statistical operations and linear algebra.
For example, we can simplify an expression, expand it or evaluate it for a
given value of x
.
Using the isSame()
method, we can compare the student's input with the
expected answer. This method returns true
if the two expressions are
structurally equivalent, and false
otherwise.
This method compares the two expressions not as strings, but as mathematical
expressions. For example, it will consider 2x
or 2\times x
to be the same.
We can make our quiz more user-friendly by allowing students to validate their answer by pressing the Enter key.
To do this, we'll add an event listener to the math input field to listen for keyboard events.
const answerField = document.getElementById('answer');
answerField.addEventListener('input', (event) => {
if (event.data === 'insertLineBreak') checkAnswer()
});
Note that we could also use the keypress
event, but the input
event is
will work both when using a physical keyboard and when using the virtual
keyboard.
In our example so far, we display the question in plain text. We can display it as LaTeX instead. It doesn't make much of a difference in this case, but it can be useful when we want to display more complex math.
First, we'll modify the HTML to indicate that a portion of the question
should be rendered as math by surrounding it with $$
delimiters.
<div>Simplify the expression: $$ (x+1)(2x-1) $$</div>
Then we'll call the renderMathInElement()
function to render the math in the question.
renderMathInElement(document.getElementById('question'));
If we had a lot of math in our quiz, we could call renderMathInDocument()
to render all the math in the page.
We also need to load a CSS stylesheet to render the math. We can use the
mathlive-static.css
stylesheet provided by the MathLive library.
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/mathlive/mathlive-static.css"
/>
Another way to render math is to use the convertLatexToMarkup()
function.
To do this, we'll modify our markup to use a <span>
element.
<p>Simplify the expression: <span id="question">(x+1)(2x-1)</span></p>
Then we'll modify our JavaScript to use this function to render the question.
const questionSpan = document.getElementById('question');
questionSpan.innerHTML =
convertLatexToMarkup(questionSpan.textContent);
Here we're using convertLatexToMarkup()
to convert the LaTeX representation
of the expression into HTML markup. It's a more direct way to render static
math in the page.
Note that we need to modify our import
statement to import the convertLatexToMarkup()
function.
import { renderMathInElement, convertLatexToMarkup } from "https://esm.run/mathlive";
So far our quiz always asks the same question. To keep it interesting, we can generate random questions.
We'll create a function that generates a product of two random terms.
function generateRandomQuestion() {
const ce = MathfieldElement.computeEngine;
const a = Math.floor(Math.random() * 10) + 1;
const b = Math.floor(Math.random() * 10) ;
const c = Math.floor(Math.random() * 10) + 1;
const d = Math.floor(Math.random() * 10) ;
// (ax+b)(cx+d)
return ce.box(["Multiply",
["Add", ["Multiply", a, "x"], b],
["Add", ["Multiply", c, "x"], d]]);
}
The ce.box()
function creates a boxed expression from a MathJSON expression.
Then we'll update our script to use this function to generate the question.
const question = generateRandomQuestion();
document.getElementById('question').innerHTML =
convertLatexToMarkup(question.latex);
const expectedAnswer = question.simplify();
Since we expect the student to have simplified the expression,
we use simplify()
to simplify the product of two terms into a polynomial and
compare it with the student's input.
Here's the complete code for our quiz application:
<!doctype html>
<html>
<head>
<title>Math Quiz</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/mathlive/mathlive-static.css"
/>
<style>
math-field {
width: 100%;
border-radius: 8px;
margin: 8px 0;
}
button {
border-radius: 8px;
padding: 8px;
margin: 8px 0;
font-size: 1em;
font-weight: bold;
font-family: system-ui;
}
p {
font-family: system-ui;
font-size: 1.5em;
padding: 8px;
}
#feedback {
font-family: system-ui;
font-size: 1.2em;
font-weight: bold;
display: flex;
justify-content: center;
padding: 8px;
border: 1px solid #ddd;
border-radius: 8px;
background: #f0f0f0;
}
</style>
</head>
<body>
<p>Simplify the expression <span id="question"></span></p>
<math-field id="answer"></math-field>
<button id="submitAnswer">Check Answer</button>
<div id="feedback"></div>
</body>
<script type="module">
import { convertLatexToMarkup } from "https://esm.run/mathlive";
import "https://esm.run/@cortex-js/compute-engine";
const ce = MathfieldElement.computeEngine;
const question = generateRandomQuestion();
const expectedAnswer = question.simplify();
document.getElementById('question').innerHTML =
convertLatexToMarkup(question.latex);
const answerButton = document.getElementById('submitAnswer');
answerButton.addEventListener('click', checkAnswer);
const answerField = document.getElementById('answer');
answerField.addEventListener('input', (event) => {
if (event.data === 'insertLineBreak') checkAnswer();
});
function generateRandomQuestion() {
const a = Math.floor(Math.random() * 10) + 1;
const b = Math.floor(Math.random() * 10) ;
const c = Math.floor(Math.random() * 10) + 1;
const d = Math.floor(Math.random() * 10) ;
// (ax+b)(cx+d)
return ce.box(["Multiply",
["Add", ["Multiply", a, "x"], b],
["Add", ["Multiply", c, "x"], d]]);
}
function checkAnswer() {
const answer = document.getElementById('answer');
const studentInput = answer.expression;
// Compare the expressions using `isSame()`
const feedback = studentInput.isSame(expectedAnswer) ?
'Correct! 😃' : 'Try again. 😞';
document.getElementById('feedback').textContent = feedback;
}
</script>
</html>
We've just scratched the surface of what's possible with MathLive and Compute Engine. This simple quiz application demonstrates the potential for creating interactive educational tools. Explore further to see how you can enhance and adapt this application to suit various educational needs.
A mathfield behaves as a regular DOM element:
- define mathfields using the
<math-field>
tag in JSX - get a reference to the corresponding DOM element with the
useRef()
hook - customize the mathfield on mount with
useEffect(..., [])
hook
To use a mathfield with React, import the MathLive library and use a <math-field>
tag.
import "https://esm.run/mathlive";
import { useState } from "react";
export default function App() {
const [value, setValue] = useState("");
return (
<div>
<math-field
onInput={evt => setValue(evt.target.value)}
>
{value}
</math-field>
<p>Value: {value}</p>
</div>
);
}
export default App;
To use a mathfield with React and TypeScript, you need to add TypeScript definitions for mathfield elements.
declare global {
namespace JSX {
interface IntrinsicElements {
'math-field': React.DetailedHTMLProps<React.HTMLAttributes<MathfieldElement>, MathfieldElement>;
}
}
}
import "https://esm.run/mathlive";
import { useState } from "react";
export default function App({children}) {
const [value, setValue] = useState<string>("");
return (
<div>
<math-field
onInput={
(evt: React.ChangeEvent<HTMLElement>) =>
setValue(evt.target.value)
}
>
{children}
</math-field>
<p>Value: {value}</p>
</div>
);
}
To specify the initial value of the mathfield provide a LaTeX
string as a child of the <math-field>
tag.
However, since both JSX and LaTeX use curly braces, you need to escape the LaTeX braces. The easiest way to do this is to use a backtick string. The content of the backtick string will be interpreted as a JavaScript string, which means that the backslashes will need to be escaped as well.
<math-field>{`
\\frac{1}{2}
`}</math-field>
To customize a mathfield, use a useRef
callback.
With the current
property of the ref, you can access and manipulate all the
properties and methods that are specific to the mathfield (value
, selection
, insert()
,
etc...). See MathfieldElement.
import "./App.css";
import "https://esm.run/mathlive";
import { useState, useEffect, useRef } from "react";
export default function App({children}) {
const [value, setValue] = useState("");
return (
<div className="App">
<math-field
ref={(el) => {
if (el === null) {
// When el is null, the mathfield is being destroyed
// You may want to unsubscribe from events here
return;
}
// Customize the mathfield when it is created
mf.current.mathVirtualKeyboardPolicy = "manual";
mf.current.addEventListener("focusin", (evt) =>
window.mathVirtualKeyboard.show()
);
mf.current.addEventListener("focusout", (evt) =>
window.mathVirtualKeyboard.hide()
}}
onInput={evt => setValue(evt.target.value)}
>
{children}
</math-field>
<p>Value: {value}</p>
</div>
);
}
date: Last Modified title: LaTeX Commands slug: /mathfield/reference/commands/ toc_max_heading_level: 2
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**.When in a Math Zone, the content is laid out using typesetting rules specific to math.
For example, variables such as
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} |
||
\textstyle Confusingly, for inline math, not for text content |
\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} |
||
\scriptscriptstyle For subscripts and superscripts of subscripts and superscripts |
\scriptscriptstyle \sum_{i=0}^n \frac{a_i}{1+x} |
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.
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.
:::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
.
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.
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.
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.
|
\char |
The argument is also a Unicode codepoint, but the { ...} delimiters are optional when using " .
|
^^ ^^^^
|
Followed by 2 or 4 hexadecimal digits with lowercase a -f to specify a Unicode codepoint.
|
:::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 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 |
\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.