Fontsampler takes care of, webfont (pre) loading, detecting variable font and woff(2) support and providing a customizable interface to manipulate type tester. It deliberately uses a bare minimum of styling for the UI so it can be adopted and styled according to the website it is embedded on.
Fontsampler aims to be a barebones solution for developers to customize. You can use your own styles, eventlisteners and layouts to create a fully customized experience. This is what an example Fontsampler looks like with basic styling and (some) features active:
A basic example
Examples
Fontsampler.js can be configured either through DOM nodes and attributes or entirely from Javascript.
For all setups include the fontsampler.js file from the dist folder:
<script src="node_modules/fontsampler-js/dist/fontsampler.js"></script>
You can configure Fontsamplers via an options object.
Bare minimum
Transform a DOM node into a simple typetester with one webfont passed:
<div id="demo">Demo minimal</div>
<script>
let node = document.getElementById("demo"),
fonts = [{
name: "Font name",
files: ["path/to/fontfile.woff2"]
}];
new Fontsampler(node, fonts).init()
</script>
Demo configuration
To configure a Fontsampler via Javascript and supply several fonts, define the UI elements and their order, you can pass in a fonts Array and options Object:
<div id="demo"></div>
<script>
let options = {
...
}
let fonts = [
…
]
Fontsampler(document.getElementById("demo"), fonts, options).init()
</script>
See details on how to use the fonts and options configuration.
Example with all options
To see what UI elements and options are available, here is a
Fontsampler instance using all available options (…hardly advisable).
Note that you can use CSS to use images for the buttons, instead of text.
Any number of variable font axes can be defined (e.g. Weight here).
Language and direction may be used to show different scripts and
localised opentype features in action.
You can also configure those attributes without rendering an
UI element for them, e.g. set a specific leading but not render
a slider.
Fonts
The webfonts to render in the Fontsampler are passed in as an Array in the Fontsampler() constructor.
When supplying several woff2/woff2variable/woff files Fontsampler will automatically serve the best option (Variable woff2 > woff2 > woff).
Fonts as Array:
// Supply fonts, even a single font, as Objects in an Array
// The order of the Array elements is the fonts’ order in the dropdown select
let node = document.getElementById("demo"),
fonts = [
// Each font is one Object inside the Array, even a single font!
{
// Provide at the very least a woff file to render. When passing in
// a woff and a woff2 file Fontsampler will determine the best font
// to use
// If you pass in more than one file or more than one woff2 file
// the first found file will be used
files: [
"path/to/font-file.woff2",
"path/to/font-file.woff",
]
// *optional
// Only used if you use the 'fontfamily' element
// Provide a nice display name for the font
name: "My font name",
// *optional
// If switching to this font should change the language,
// define the language choice value
language: "enGB",
// *optional
// If switching to this font should change the text direction,
// define the direction choice value
direction: "ltr"
// *optional
// If switching to this font should change the features,
// define the features choice value
features: ["liga", "dlig", "ss01"]
// *optional, for variable fonts only
// Define the variable font axes location this instance represents
instance: {
"wght": 400,
"opsz": 12
}
// *optional, the 'cls' and 'family' attributes used together let you
// match an exising CSS font face to re-use, instead of loading the fonts
// with the Fontface Javascript API
cls: "some-class",
family: "The CSS Font Family",
// *optional
// Define a CSS font family which should be applied to the input field as
// fallback font — characters not in the loaded webfont will be rendered
// in this font (this fallback font has to be available on the page)
fallback: "My Fallback Font"
},
{
…another font…
}
]
new Fontsampler(node, fonts).init()
The same options can also be passed in as a data-fonts attribute on the DOM node in JSON notation. Defining complex fonts arrays like this is, of course, quite unwiedly — but possible.
<div id="demo" data-fonts="[{ 'files': [path/to/font-name.woff] }]">
Demo minimal
</div>
<script>
new Fontsampler(document.getElementById("demo")).init()
</script>
Options
You can pass in an options object that will overwrite the below defaults. If you omit some of the options, defaults will be used.
The order option can be used to define the UI elements’ DOM structure. Use nested Arrays to group elements into the same wrapper element.
Here is a full list of all default options (and values):
// Leave empty to set no text or inherit the DOM node’s current text
initialText: "",
// Set false to force single line input
multiline: true,
// Set true to preloaded all fonts in the Fontsampler in the background
// instead of only loading them when activated
lazyload: false,
// Define the order and presence of UI elements
// Use nested Arrays to group elements into the same wrapper to
// put them on the same "line"
// All these elements have predefined UI and functionality that can be
// customized below in the config option to overwrite the defaults
// Any element that appears here will be rendered!
order: [
["fontsize", "lineheight", "letterspacing"],
["fontfamily", "language"],
["alignment", "direction", "opentype"],
"tester",
// Variable fonts note: Add any axis tag for which to show a
// slider as element, in whatever spot you want to display them, e.g.
["wght", "opsz", "slnt"]
],
// Definitions for each UI element
// Any nested element can also be only partially defined, which will make it inherit
// the rest of its configuration from the defaults
config: {
// The actual input element for testing the webfonts
tester: {
// Set’s the contenteditable attribute
editable: true,
// The tester has it’s label disabled by default
label: false
},
// The font-size slider
fontsize: {
// Any CSS unit is valid (e.g. px, em, %, etc.)
unit: "px",
// These values are defined without a unit!
init: 18,
min: 12,
max: 96,
step: 1,
// The text label to render for the element, set any label to false
// to disable rendering that label altogether
label: "Size"
},
// The line-height slider
lineheight: {
unit: "%",
init: 100,
min: 60,
max: 120,
step: 5,
label: "Leading"
},
// The letter-spacing slider
letterspacing: {
unit: "em",
init: 0,
min: -1,
max: 1,
step: 0.05,
label: "Letterspacing"
},
// The drop-down for picking fonts
fontfamily: {
label: "Font",
// Supply the exact name of the Font (fontname, not file!) to be selected
// and loaded first, by default the first font passed in
init: ""
},
// The set of buttons controlling alignment
alignment: {
// Choices can an Array of strings used both as value and display label
// or the strings are separated by | to use as value|Display label
choices: ["left|Left", "center|Centered", "right|Right"],
// Has to be one of the above choices
init: "left",
label: "Alignment"
},
// The script direction, options like alignment
direction: {
choices: ["ltr|Left to right", "rtl|Right to left"],
init: "ltr",
label: "Direction"
},
// The language dropdown setting the html lang attribute, thus triggering
// opentype locl features
language: {
choices: ["enGB|English", "deDe|Deutsch", "nlNL|Dutch"],
init: "enGb",
label: "Language"
},
// A set of checkboxes; NOTE: No validation whatsoever if the font
// supports these opentype features
opentype: {
choices: ["liga|Ligatures", "frac|Fractions"],
init: ["liga"],
label: "Opentype features"
}
// Variable fonts note: Add any axis tag for which to configure a
// slider as element, e.g.
wght: {
init: 400,
min: 250,
max: 900,
step: 10,
label: "Weight",
}
…
},
// CSS classes for various elements and states
classes: {
// See the values and defaults below
// The root element on which Fontsampler was initiated
rootClass: "fontsamplerjs",
…
}
Styling
Fontsampler JS aims to be as light-weight as possible. You can use the Javascript library without any dependencies and Fontsampler JS will render all the DOM elements needed (without styling).
If you wish to apply a sensible minimum styling you can include the css (or scss file). If you further wish to enhance the basic HTML controls used in the UI (<input type="range">, <input type="checkbox">, <select>, and <button>) you can further include and apply the shipped Skin. This skin includes a few lightweight Javascript modules to transform the UI controls. Feel free to build your own Skin module using the built in as a sample.
Use the Javascript module without styling
<script src="node_modules/fontsampler-js/dist/fontsampler.js"></script>
…
<div id="demo">Hello world</div>
…
<script>
let fs = Fontsampler(document.getElementById("demo"), fonts, options)
fs.init()
</script>
Use the Javascript module with CSS styling and a UI skin
<script src="node_modules/fontsampler-js/dist/fontsampler.js"></script>
<script src="node_modules/fontsampler-js/dist/fontsampler-skin.js"></script>
<link rel="stylesheet" href="node_modules/fontsampler-js/dist/fontsampler-skin.css" >
…
<div id="demo">Hello world</div>
…
<script>
let fs = Fontsampler(document.getElementById("demo"), fonts, options)
FontsamplerSkin(fs)
fs.init()
</script>
With or without skin, the minimal default CSS for Fontsampler is written so that styles from the container or website it is on are inherited as much as possible. For example this Fontsampler will inherit (the rather tasteless) font and color styling from this container:
For the Skinned version you will obviously want to overwrite the custom Slider, Dropdown abd Button elements’ styling.
Styling classes
You can use some default CSS classes to style Fontsampler or pass in custom classes to use instead.
// The root element on which Fontsampler was initiated
rootClass: "fontsamplerjs",
// Root element class after the Fontsampler has been initialized
initClass: "fsjs-initialized",
// Root element class while loading a webfont file
loadingClass: "fsjs-loading",
// Root element class while preloading (e.g. ´lazyload´ is true and
// not all fonts have preloaded yet)
preloadingClass: "fsjs-preloading",
// Any Array wrapper in the ´order´ attribute will generate a wrapper
// with this class
wrapperClass: "fsjs-wrapper",
// The wrapper of each UI element around label and UI
// For each UI element this base also is used to create a class:
// fsjs-block-element (e.g. elements are "fontsize", "lineheight", etc.)
// For each UI element this base also is used to create a UI type class:
// fsjs-block-type-type (e.g. types are "slider", "checkboxes", "buttongroup", "textarea")
blockClass: "fsjs-block",
// Every ´ui´ element receives this class
elementClass: "fsjs-element",
// Classes for the label of various UI elements
labelClass: "fsjs-label",
labelTextClass: "fsjs-label-text",
labelValueClass: "fsjs-label-value",
lableUnitClass: "fsjs-label-unit",
// All multi-option buttons
buttonClass: "fsjs-button",
// The selected button’s class in a buttongroup
buttonSelectedClass: "fsjs-button-selected",
<style type="text/css">
/* Fontsampler provides classes for when a font is loading (e.g. to display
a spinner or fade out the text tester while the font is loading) */
.fontsamplerjs.loading {…}
/* If you use the lazyload option you can use this class to change appearance
while some fonts are still loading in the background */
.fontsamplerjs.preloading {…}
/* The Fontsampler has initialized */
.fontsamplerjs.fontsampler-initiallized {…}
/* When Fontsampler groups items together as per the definitions (nested arrays)
in the options attribute, those wrappers will have this class */
.fsjs-wrapper {…}
/* Any UI element (controls, tester input) */
.fsjs-block {…}
/* All UI elements have their key as class */
.fsjs-block-fontsize,
.fsjs-block-tester,
… {…}
/* All UI types have a class, e.g. slider, dropdown, buttongroup, checkboxes, textarea */
.fsjs-block-type-buttongroup {…}
/* UI elements with labels have markup for the label and it’s content */
.fsjs-block-fontsize [data-fsjs-for=fontsize] {…}
.fsjs-block-fontsize [data-fsjs-for=fontsize] .fsjs-label-text {…}
.fsjs-block-fontsize [data-fsjs-for=fontsize] .fsjs-label-value {…}
.fsjs-block-fontsize [data-fsjs-for=fontsize] .fsjs-label-unit {…}
</style>
You can overwrite many classes by passing in an options object. Note that the default skin relies on many of the default classes!
<script>
let options = {
…
classes: {
rootClass: "fontsamplerjs",
wrapperClass: "fsjs-wrapper",
loadingClass: "fsjs-loading",
preloadingClass: "fsjs-preloading",
…
}
…
}
</script>
Events & API
Fontsampler instances have a variety of methods and events for programmatic manipulation. To demo these, below Fontsampler shows all events and exposes API methods as buttons.
Miscellaneous other samples
Fallback font
You can define the name of a font-family to serve as fallback font for characters not supported by the current webfont. This can be a browser default font, or a webfont you know is loaded on the page regardless of Fontsampler.
let fonts = [{
"name": "Alegreya Regular",
"files": ["./fonts/alegreya/alegreya-v12-latin-regular.woff"],
"fallback": "Arial"
}]
Lazyloading
Setting the lazyload option to true Fontsampler will initiate with the first font and then preload any other fonts in the Fontsampler in the background. If the font is switched before all fonts have loaded the requested font will be the next to be loaded and displayed.
<script>
let options = {
lazyload: true
}
…
new Fontsampler(document.getElementById("demo"), fonts, options).init()
</script>
By default Fontsampler JS only loads the fonts on display as needed, always initiating with the first font. If a Fontsampler has more than one fonts, the other fonts are only loaded when a user selects them.
See the lazyloading example page (use your browser developer tools’ network throttling and network tab to see what’s going on).
Inserting DOM elements
If you have a need to insert some custom DOM node into the Fontsampler UI, for example to implement some additional custom UI control or insert a link or decorative element. You can pass in a reference to any HTMLElement and insert that node in the order at the location you would like it rendered. The node is removed from the DOM Tree and re-inserted in the rendered Fontsampler wrapped in a div which inherits the original node’ id! Apply custom styling as needed.
<!-- somewhere outside the Fontsampler DOM node -->
<button id="custom-bottom">Custom button</button>
<img id="custom-image" src="…" />
<div id="demo">Hello custom DOM elements</div>
<script>
// Get the HTMLElement (use getElementById, querySelector, etc.)
// It is important to pass in a single node, not an Array/Selection
let customButton = document.getElementById("custom-button")
let customImage = document.getElementById("custom-image")
let fonts = […]
let options = {
order: [
// Note that you are passing a reference to the actual HTMLElement, not its id!
[customImage, "fontsize", "lineheight"],
["fontfamily", "alignment", customButton],
["tester"],
]
}
new Fontsampler(document.getElementById("demo"), fonts, options).init()
</script>