Custom Fonts — Reference
The Custom Fonts surface is the self-hosted typeface registry — the place where an operator uploads a foundry-licensed font, a variable-axis family, or a non-Google web font that the styles-and-layouts font pickers should expose. It complements the platform's built-in Google Fonts discovery: Google fonts come in for free via the discovery list, and anything outside that list comes in through here.
This page is a reference for platform engineers and integrators who need to understand the upload pipeline, the file-format normalization, and how custom fonts surface into the SG-Builder editor and the global styles. Customer-facing walkthroughs for uploading a font and applying it live in the customer docs set.
Overview
Custom Fonts lives under the Custom module group in SG-Admin, alongside its design-system siblings Custom CSS and Custom Codes, and the operator-data siblings Custom Fields and Custom Objects.
The module is paired by convention: one half renders the list, create, edit, manage-font views; the other half handles writes — upload, table refresh, soft delete, restore. The list view shows each font family with its uploaded weights and styles, a preview rendered in the font itself, and the destination registry — whether it appears in the styles-and-layouts font picker, the SG-Builder typography picker, or both.
A font record carries a family name, a display name, the set of uploaded files (one per weight × style), a fallback stack, a load strategy (swap, block, fallback, optional), an enabled flag, and a unicode-range hint. On render, the platform emits an @font-face rule per file into the active stylesheet and offers the family in the relevant typography pickers.
Where it lives in SG-Admin:
- Sidebar: SG-Admin → Custom → Fonts
- URL prefix:
/sg-admin/custom-fonts/ - View templates:
application/views/Admin/CustomFonts/
Inter Site instead of plain Inter — so the picker shows both clearly. The surface returns a structured rejection on duplicate family names.Self-hosted vs Google route. For Google's catalog, the recommended path is the Google Fonts URL field in the styles-and-layouts editor — fonts come in via the Google CDN with no upload required. Use Custom Fonts when the foundry is not Google, when the typeface needs to be self-hosted for compliance or performance reasons, or when a variable-axis font is needed (Google's basic URL field does not expose the full axis range).
┌──────────────────────────────────────────────────────────────────────┐│ SG-Admin → Custom → Fonts [+ Upload] │├──────────────────────────────────────────────────────────────────────┤│ Family Weights / Styles Format Status ││ ────────────────── ──────────────────────── ────── ─────── ││ Söhne (licensed) 400, 500, 600, 700 · i WOFF2 active ││ Inter Variable 100-900 axis WOFF2 active ││ Brand Serif Pro 300, 400, 700 WOFF2, active ││ WOFF ││ Old Display (paused) 400 WOFF2 paused ││ ││ ┌──────────────────────────────────────┐ ││ │ Preview: │ ││ │ Söhne — The quick brown fox jumps │ ││ │ Inter Variable — The quick brown fox │ ││ │ Brand Serif Pro — The quick brown │ ││ └──────────────────────────────────────┘ │└──────────────────────────────────────────────────────────────────────┘Actions
The Custom Fonts surface exposes the following operations.
List and search
Returns the font records visible to the operator, paginated, with family, uploaded weight/style coverage, format, status, and last-modified columns. Includes a live preview block that renders the family in itself for visual confirmation. Supports sort, free-text filter on family name, and filter by status or format.
Upload font (create)
Opens an upload form. Required fields: family name (must be unique), display name, at least one font file. Optional: fallback stack, load strategy, unicode-range hint, weight and style metadata per file (auto-detected when the file's internal name table is well-formed, manually entered otherwise).
Files accepted: WOFF2 (preferred), WOFF, TTF, OTF. On upload, the platform normalizes each file — converts TTF and OTF to WOFF2, generates a WOFF fallback, computes file size, extracts the internal name table for metadata, and writes the files to the platform CDN with cache-control headers tuned for fonts.
Edit font
Loads an existing record into the same form shape used for upload, pre-populated. Operators can add new weight/style files to an existing family, remove individual files, update the fallback stack, or change the load strategy. Submit replaces the stored record; removed files are scheduled for CDN purge.
Manage font (per-family detail)
A detail view per family. Shows every uploaded file with weight, style, format, file size, the resolved @font-face source URL, and a per-file enabled flag. Useful for partial activation — for example, uploading 12 weights but exposing only 4 in the typography pickers.
Toggle enabled
Pauses or resumes a font without deleting it. A paused family is omitted from the typography pickers and the @font-face emission.
Soft delete
Marks the family as trashed. Trashed families disappear from the default list and stop rendering immediately. Pages that referenced the font fall through to the next item in their fallback stack until the reference is updated.
Restore
Returns a trashed family to its prior enabled state. CDN files are reactivated; no re-upload is required.
Permanent delete
Hard-removes a trashed family and purges its CDN files. Irreversible.
Data model
A font family record carries the following fields, with one nested file record per uploaded weight × style.
| Field | Type | Notes |
|---|---|---|
id | integer | Primary key. Stable across edits. |
family_name | string | Unique. Picker index key. |
display_name | string | List-view label. Not unique. |
files[] | array | One per uploaded weight × style. See below. |
fallback_stack | string | CSS-style stack — "system-ui, sans-serif" etc. |
load_strategy | enum | swap, block, fallback, optional. Renders as font-display in @font-face. |
unicode_range | string | Optional. Renders as unicode-range in @font-face. |
surface_destination | enum | picker-only, styles-and-layouts, sg-builder, both. |
enabled | boolean | true emits @font-face and exposes in pickers. |
status | enum | active or trash. |
created_at | timestamp | Immutable. |
updated_at | timestamp | Touched on edit. |
created_by | integer | Foreign key to Users. |
files[]):| Field | Type | Notes |
|---|---|---|
id | integer | Primary key on the file row. |
weight | integer | 100-900. Or 1-1000 for variable-axis. |
style | enum | normal or italic. |
format | enum | woff2, woff, ttf, otf. |
url | string | CDN-served URL. Stable across edits. |
byte_size | integer | Post-normalization size. |
file_enabled | boolean | Per-file toggle, independent of family-level. |
@font-face uses the normalized WOFF2 + WOFF pair.Variable axis fonts. A variable font occupies a single file with a weight range. The weight field on the file record carries the range (100-900) rather than a single value. Typography pickers expose the full range to operators selecting weight.
FONT FAMILY RECORD FILES (nested array)├── id ┌─── per weight × style ───┐├── family_name (unique) │ │├── display_name │ ├── weight 400 │├── fallback_stack │ ├── style normal │├── load_strategy │ ├── format woff2 │├── unicode_range │ ├── url <CDN> │├── surface_destination │ ├── byte_size │├── enabled │ └── file_enabled │├── status │ │└── timestamps │ ── repeated for each ── ││ weight / style / │on render: │ format combination │emit @font-face per └──────────────────────────┘enabled fileexpose family inconfigured pickersPermissions
Access to the Custom Fonts surface is gated at two layers.
Layer 1 — admin gate. Standard admin access check at request entry.
Layer 2 — per-action capability. The default capability map ships as:
| Capability | Administrator | Editor | Designer | Viewer |
|---|---|---|---|---|
| List fonts | ✔ | ✔ | ✔ | ✔ |
| Upload font | ✔ | — | ✔ | — |
| Edit font | ✔ | — | ✔ | — |
| Manage font (per-file) | ✔ | — | ✔ | — |
| Toggle enabled | ✔ | — | ✔ | — |
| Soft delete | ✔ | — | ✔ | — |
| Restore | ✔ | — | ✔ | — |
| Permanent delete | ✔ | — | — | — |
Self-protection rules. The surface returns a structured rejection on duplicate family names, on file uploads that fail the format-normalization step (corrupt or unsupported source), and on a permanent delete attempt while any active CSS rule still references the family (use a search-and-replace pass first).
License audit. The original uploaded file is retained on the CDN under the family for the lifetime of the record. Operators uploading licensed fonts should attach the license document or invoice to the family's notes field — there is no automated license enforcement, only the audit trail.
Audit. Every upload, edit, manage-font change, toggle, soft delete, restore, and permanent delete emits an Activity Log entry. The diff includes the file set before and after — useful for tracking when a weight was added or removed.
UPLOAD → /sg-admin/custom-fonts/...│▼┌──────────────────────┐│ Admin gate │└──────────┬───────────┘│▼┌──────────────────────┐│ Capability check ││ Designer / Admin │└──────────┬───────────┘│▼┌──────────────────────┐│ Family-name unique? │ duplicate → reject└──────────┬───────────┘│▼┌──────────────────────┐│ Format normalize │ corrupt/unsupported → reject│ TTF/OTF → WOFF2 ││ generate WOFF │└──────────┬───────────┘│▼┌──────────────────────┐│ CDN upload ││ cache-control set │└──────────┬───────────┘│▼record persists│▼Activity Log entry│▼emit @font-face on next renderexpose in configured pickersRelated references
- Themes — Reference. Styles-and-layouts is one of the destination pickers. Custom Fonts surface into the heading, body, and accent role pickers there.
- Custom CSS — Reference. Operator rules can reference uploaded families by their
family_namedirectly. The platform-emitted@font-faceblock is global; no extra import is needed. - Custom Codes — Reference. Not the right surface for font hosting. Use this module — the load-strategy and CDN caching are tuned for fonts in a way that ad-hoc Custom Code uploads are not.
- Pages — Reference. Pages that override the global font stack pick from the same registry exposed by this module.
- SG-Builder — Reference. The Builder editor's typography picker surfaces fonts registered with
surface_destinationset tosg-builderorboth. - Settings — Reference. CDN configuration, license-audit retention, font upload byte cap.
/docs/custom-fonts.