---
title: "Icons"
manual: "Academic Base"
version: "main"
permalink: "https://docs.typo3.org/permalink/fgtclb/academic-base:icons@main"
source: "Icons/Index.rst"
rendered: "2026-10-17T08:47:46+00:00"
---

# Icons {#icons}

This extension ships the icons the academic extensions share: the actions of a
control, the states a control shows, and the glyphs in front of a piece of
information such as a phone number or an address. An icon that means the same
in several extensions exists once, here, so a site package that replaces it
replaces it everywhere.

They are frontend icons. They are registered in the frontend icon registry of
this extension, in its `Configuration/FrontendIcons.php`, and the
templates of the academic extensions render them with the view helper
`ab:icon`, see [Frontend icons](https://docs.typo3.org/permalink/fgtclb/academic-base:configuration-frontend-icons@main). The
backend does not show them, and the icon registry of TYPO3 does not know them.

Every icon is a Font Awesome Free icon of the solid style, drawn in
`currentColor` and registered with
`\FGTCLB\AcademicBase\Imaging\IconProvider\CurrentColorSvgIconProvider`
(see [Icons that follow the text colour](https://docs.typo3.org/permalink/fgtclb/academic-base:configuration-icon-provider@main)).
It therefore takes the colour of the text around it, and it sizes itself by
the font size: every file carries `width="1em"` and `height="1em"`.

## Identifiers and files {#icons-naming}

The identifiers follow `tx-<extension key without underscores>-<group>-<name>`,
the files `Resources/Public/Icons/<group>/<name>.svg`. This extension
uses three groups:

-   `action`, something a control does,
-   `state`, a state a control shows,
-   `info`, the glyph in front of a piece of information.

The other academic extensions name their icons the same way. The group decides
the registry: an `action`, `state` or `info` icon is a frontend icon,
registered in `Configuration/FrontendIcons.php`, and a `record`,
`plugin` or `doktype` icon, the icon of a record type, a content element or a
page type, is a backend icon, registered in [`Configuration/Icons.php`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/Configuration/Icons.html#file-extension-configuration-icons-php).
The icons of category types and category groups are the exception: their
identifiers are derived by `EXT:category_types` from the
`Configuration/CategoryTypes.yaml` that declares them, and they reach
both registries. Their files live in the directories `category-type/`
and `category-group/`, or are files of this set.

The tables below give the file relative to
`EXT:academic_base/Resources/Public/Icons/` and the name of the icon in
Font Awesome.

## Actions {#icons-actions}

| Identifier | Meaning | File | Font Awesome |
| --- | --- | --- | --- |
| `tx-academicbase-action-add` | Add an item | `action/add.svg` | `plus` |
| `tx-academicbase-action-back` | Go back | `action/back.svg` | `arrow-left` |
| `tx-academicbase-action-clear` | Clear a field | `action/clear.svg` | `eraser` |
| `tx-academicbase-action-close` | Close or dismiss | `action/close.svg` | `xmark` |
| `tx-academicbase-action-collapse` | Collapse a section | `action/collapse.svg` | `minus` |
| `tx-academicbase-action-delete` | Delete an item | `action/delete.svg` | `trash-can` |
| `tx-academicbase-action-drag` | Drag-and-drop handle | `action/drag.svg` | `grip-lines` |
| `tx-academicbase-action-edit` | Edit | `action/edit.svg` | `pen` |
| `tx-academicbase-action-expand` | Expand a section | `action/expand.svg` | `plus` |
| `tx-academicbase-action-help` | Show or hide a help text | `action/help.svg` | `circle-question` |
| `tx-academicbase-action-move-down` | Move one position down | `action/move-down.svg` | `arrow-down` |
| `tx-academicbase-action-move-up` | Move one position up | `action/move-up.svg` | `arrow-up` |
| `tx-academicbase-action-save` | Save | `action/save.svg` | `floppy-disk` |
| `tx-academicbase-action-undo` | Undo or reset | `action/undo.svg` | `rotate-left` |
| `tx-academicbase-action-upload-image` | Upload or replace an image | `action/upload-image.svg` | `camera` |
| `tx-academicbase-action-view` | Show a preview | `action/view.svg` | `eye` |
| `tx-academicbase-action-view-close` | Close the preview | `action/view-close.svg` | `eye-slash` |

## States {#icons-states}

| Identifier | Meaning | File | Font Awesome |
| --- | --- | --- | --- |
| `tx-academicbase-state-hidden` | Item is hidden (switch off) | `state/hidden.svg` | `toggle-off` |
| `tx-academicbase-state-visible` | Item is visible (switch on) | `state/visible.svg` | `toggle-on` |

## Information {#icons-information}

| Identifier | Meaning | File | Font Awesome |
| --- | --- | --- | --- |
| `tx-academicbase-info-calendar` | Date | `info/calendar.svg` | `calendar-days` |
| `tx-academicbase-info-company` | Company or institution | `info/company.svg` | `building` |
| `tx-academicbase-info-contract` | Contract | `info/contract.svg` | `file-contract` |
| `tx-academicbase-info-degree` | Degree | `info/degree.svg` | `graduation-cap` |
| `tx-academicbase-info-department` | Department or faculty | `info/department.svg` | `building-columns` |
| `tx-academicbase-info-email` | E-mail | `info/email.svg` | `envelope` |
| `tx-academicbase-info-employment` | Employment or job | `info/employment.svg` | `briefcase` |
| `tx-academicbase-info-information` | Additional information | `info/information.svg` | `circle-info` |
| `tx-academicbase-info-international` | International | `info/international.svg` | `earth-europe` |
| `tx-academicbase-info-link` | Link | `info/link.svg` | `link` |
| `tx-academicbase-info-location` | Location or address | `info/location.svg` | `location-dot` |
| `tx-academicbase-info-partnership` | Partnership or cooperation | `info/partnership.svg` | `handshake` |
| `tx-academicbase-info-person` | Person, a contact | `info/person.svg` | `user` |
| `tx-academicbase-info-phone` | Phone | `info/phone.svg` | `phone` |
| `tx-academicbase-info-recommendation` | Recommendation | `info/recommendation.svg` | `star` |
| `tx-academicbase-info-role` | Role | `info/role.svg` | `user-tag` |
| `tx-academicbase-info-room` | Room | `info/room.svg` | `door-open` |
| `tx-academicbase-info-sector` | Sector or industry | `info/sector.svg` | `industry` |
| `tx-academicbase-info-time` | Time, office hours | `info/time.svg` | `clock` |

`expand` and `add` are the same drawing in two files, so a site package can
replace one without the other.

Five of the nineteen information identifiers are rendered by a template of
the academic extensions: `-info-email`, `-info-phone`, `-info-location`,
`-info-room` and `-info-time`. The other fourteen stay registered on purpose,
so a site package can render and replace them like the others. The job views
render identifiers of **academic_jobs** that draw the same files, and
several files are also the drawings of record and category type icons, which
other academic extensions register under identifiers of their own. A
replacement of one of the fourteen therefore changes neither the job views nor
those record and category type icons.

## Rendering an icon {#icons-usage}

In a Fluid template of the frontend, with the view helper of this extension:

**EXT:my_sitepackage/Resources/Private/Partials/Contact.html**

```html
<html xmlns:ab="http://typo3.org/ns/FGTCLB/AcademicBase/ViewHelpers"
      data-namespace-typo3-fluid="true">

<ab:icon identifier="tx-academicbase-info-phone" alternativeMarkupIdentifier="inline" />

</html>
```

The markup is the inlined file with or without
`alternativeMarkupIdentifier="inline"`, because the provider inlines both
markups. The argument keeps the icon inlined where a site package replaces it
with the core `\TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider`,
which inlines the file only when it is asked to.

The rendered icon carries the CSS class `icon-<identifier>`, for example
`icon-tx-academicbase-info-phone`, and the attribute `data-identifier`. A
stylesheet can address it through either. `<core:icon>` does not render
these icons: it reads the icon registry of TYPO3 and shows its not-found icon
for them.

## Replacing an icon in a site package {#icons-override}

Register the same identifier again in
`Configuration/FrontendIcons.php` of the site package. The later
registration wins, and every template of every academic extension that renders
the identifier shows the replacement:

**EXT:my_sitepackage/Configuration/FrontendIcons.php**

```php
return [
    'tx-academicbase-info-phone' => [
        'provider' => \FGTCLB\AcademicBase\Imaging\IconProvider\CurrentColorSvgIconProvider::class,
        'source' => 'EXT:my_sitepackage/Resources/Public/Icons/phone.svg',
    ],
];
```

-   The site package has to load after this extension: it requires
    [`fgtclb/academic-base`](https://packagist.org/packages/fgtclb/academic-base), or an academic extension, which requires
    it, in its `composer.json`, and in classic mode names it under
    `depends` in its `ext_emconf.php` as well. The files are read in the
    loading order of the packages, and without the dependency the site package
    may be read first and lose.
-   The entry replaces the whole registration, provider and source alike.
-   Keep the replacement drawable for inlining if it stays with
    `CurrentColorSvgIconProvider`: a `viewBox`, `currentColor`, no `id`
    and no `<style>`, see
    [What the SVG file must look like](https://docs.typo3.org/permalink/fgtclb/academic-base:configuration-icon-provider-svg@main).
-   Flush the system caches afterwards.

An entry in [`Configuration/Icons.php`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/Configuration/Icons.html#file-extension-configuration-icons-php) changes nothing in the frontend,
the frontend registry does not read that file. The record, content element and
page type icons of the academic extensions are the other way round: they are
backend icons, and a site package replaces them in its
[`Configuration/Icons.php`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/Configuration/Icons.html#file-extension-configuration-icons-php).

## Icons in frontend JavaScript {#icons-frontend-javascript}

The backend JavaScript icon API of TYPO3 cannot be used on a frontend page: it
asks a backend route that answers a logged-in backend user only, and it serves
the icon registry of TYPO3. Frontend JavaScript therefore takes the markup of
an icon of the frontend icon registry from the server.

> [!NOTE]
> The contracts this section documents are public API of this extension,
> as the [extension points page](https://docs.typo3.org/permalink/fgtclb/academic-base:developers-extension-points-api@main)
> lists them. They change only in a major release, with a Breaking
> changelog entry. The PHP classes behind them are not public API.

Where the JavaScript stamps out a piece of markup anyway, a list item or a row
with its buttons, render the icon with `ab:icon` into a `<template>`
element and clone it. Where it picks an icon by its identifier at runtime,
hand it the icons it may need as a JSON map:

```html
<html xmlns:ab="http://typo3.org/ns/FGTCLB/AcademicBase/ViewHelpers"
      data-namespace-typo3-fluid="true">

<ab:frontendIconMap identifiers="{0: 'tx-academicbase-action-add', 1: 'tx-academicbase-action-delete'}" />
```

This renders a JSON data block that the browser neither executes nor checks
against the Content Security Policy:

**Shortened**

```html
<script type="application/json" data-academic-icons data-academic-icons-size="small">{"tx-academicbase-action-add":"\u003Cspan class=\u0022t3js-icon icon icon-size-small ...\u0022 ...\u003E...\u003C/span\u003E","tx-academicbase-action-delete":"..."}</script>
```

Each value is the markup `<ab:icon identifier="..."
alternativeMarkupIdentifier="inline" />` renders, so the replacement of an icon
in a site package arrives in the JavaScript as it does in a template. The JSON
escapes `<`, `>`, `&` and both quotes as unicode escapes, so no markup can end
the element, and `JSON.parse()` returns the plain markup.

Arguments:

-   **`identifiers` (array, required)**

    The identifiers to render. One that is not served is left out of the map,
    see below.

-   **`size` (string, default `small`)**

    `default`, `small`, `medium`, `large` or `mega`. It sets the `icon-size-*`
    class of the markup. The icons of the academic extensions size themselves
    by the font size.

-   **`endpoint` (bool, default `false`)**

    Adds `data-academic-icons-url` and `data-academic-icons-version` to the
    element: the [icon endpoint](https://docs.typo3.org/permalink/fgtclb/academic-base:icons-frontend-endpoint@main) of the current
    site language and the version token of the served icons. Outside a site
    both are left out.

### The icon endpoint {#icons-frontend-endpoint}

Where the JavaScript learns an identifier only after the page was rendered,
from data it loads or from a choice of the visitor, it asks the icon endpoint
of the site:

```text
GET https://example.com/_academic/icons.json?i=tx-academicbase-action-add,tx-academicbase-info-phone&s=small&v=<token>
```

The answer is a JSON object in the same shape as the JSON map, for the
identifiers that are served, in the order asked for. The endpoint is available
below the base of every site and site language, for example
`https://example.com/de/_academic/icons.json`. Its path, its parameters, its
answer and its caching are public API like the rest of this section.

-   **`i` (required)**

    Up to 32 icon identifiers, separated by commas.

-   **`s` (optional, default `small`)**

    `default`, `small`, `medium`, `large` or `mega`.

-   **`v` (optional)**

    The version token of the served icons, as `data-academic-icons-version`
    of the JSON map carries it. With the current token the answer may be
    cached for a year (`Cache-Control: public, max-age=31536000, immutable`),
    otherwise for five minutes. The answer carries an `ETag` and answers a
    matching `If-None-Match` with `304 Not Modified`. The `ETag` only helps
    the five-minute answers, an immutable one is never revalidated.

A malformed identifier, more than 32 of them or an unknown size are answered
with `400 Bad Request`, any method other than `GET` and `HEAD` with
`405 Method Not Allowed`. The endpoint answers before the frontend user
authentication: it never starts a session and never sets a cookie, so a proxy
or a CDN can cache it like a file. A site in maintenance mode answers it with
`503`, like every page.

The token covers what decides the markup of a served icon:

-   the identifiers the frontend icon registry serves and their
    registrations, so a site package that replaces an icon changes it once the
    system caches are flushed,
-   the modification time of each source file,
-   the modification time of the class files of each provider and of the
    classes it extends, so a provider changed in place changes it as well,
-   TYPO3's package dependent cache identifier: the TYPO3 version, the project
    path and, in composer mode, the content of `composer.lock`.

A deployment that writes the files anew therefore changes the token, and the
browsers fetch the icons once more. Not covered is other rendering code
changed in place without any of these, the icon markup of TYPO3 or the SVG
sanitiser library edited on the server. Touch the SVG files of the affected
icons then.

Each web node computes the token from its own file times and project path, so
nodes that do not share one build compute different tokens, and a page
rendered on one node gets the five-minute answer from another.

> [!IMPORTANT]
> **Web server requirement.** The path ends in `.json`. A web server or CDN
> rule that serves `*.json` as static files, in nginx for example a
> `location ~* .(...|json)$` with `try_files $uri =404`,
> answers the endpoint with a `404` before TYPO3 sees it. Exclude
> `_academic/icons.json` from such a rule, the way `sitemap.xml` is usually
> excluded.

### The icon factory {#icons-frontend-factory}

Both are read by the JavaScript module
`@fgtclb/academic-base/frontend/icons.js`, which this extension publishes in
its import map. The module and its exports are public API like the rest of
this section.
A module asks it for an icon by its identifier. The factory answers from the
JSON maps of the page and asks the endpoint only for what the page does not
carry, collecting the icons asked for at the same time into one request. The
request names them sorted by identifier, so the same icons always make the
same URL and a browser or a proxy caches their answer once:

**The template of the plugin**

```html
<div class="my-plugin" data-my-plugin>
    <ab:frontendIconMap identifiers="{0: 'tx-academicbase-action-add'}" endpoint="1" />
</div>
<f:asset.module identifier="@my-vendor/my-sitepackage/frontend/my-plugin.js" />
```

**The module of the plugin**

```javascript
import { IconFactory, Sizes, endpointFrom } from '@fgtclb/academic-base/frontend/icons.js';

const root = document.querySelector('[data-my-plugin]');
const icons = new IconFactory(endpointFrom(root));

// From the JSON map of the page, without a request.
button.append(await icons.getIconElement('tx-academicbase-action-add'));
// From the endpoint, in one request for both.
const [edit, remove] = await Promise.all([
    icons.getIcon('tx-academicbase-action-edit', Sizes.medium),
    icons.getIcon('tx-academicbase-action-delete', Sizes.medium),
]);
```

The extension or site package that ships the module has to name
`academic_base` in the dependencies of its import map. A page only carries the
import map entries of the packages its modules declare:

**EXT:my_sitepackage/Configuration/JavaScriptModules.php**

```php
return [
    'dependencies' => ['core', 'academic_base'],
    'imports' => [
        '@my-vendor/my-sitepackage/frontend/' => 'EXT:my_sitepackage/Resources/Public/JavaScript/frontend/',
    ],
];
```

`getIcon()` answers the markup, `getIconElement()` a new element on every call,
and `prefetch()` asks for several icons ahead of time. An identifier that is
not served, or that is not an icon identifier at all, rejects the promise. A
malformed one is never sent, so it cannot fail the icons asked for with it.
The factory reads every JSON map of the document, not only those inside the
element it was given, and the first map that carries an icon wins. An icon the
endpoint leaves out stays rejected for the page, unless a JSON map that
reaches the page later carries it.
Each icon is asked for once per page, without cookies. A request that fails or
gets no answer within ten seconds rejects its icons, and the next call asks
again. The browser keeps the answer of the endpoint as long as the token does
not change.

### Which icons are served {#icons-frontend-served}

The JSON map and the endpoint serve the same icons. The icons of the frontend
icon registry, and no other: what the
`Configuration/FrontendIcons.php` of an extension or a site package
registers, what a listener of [CollectFrontendIconsEvent](https://docs.typo3.org/permalink/fgtclb/academic-base:developers-event-collect-frontend-icons-event@main) contributes, and
the icons of category types and category groups. The icon registry of TYPO3 is
never read, so a core icon or the backend icon of a record type is not served,
even when a template asks for its identifier. A site package hands an icon of
its own to its JavaScript by registering it in its
`Configuration/FrontendIcons.php`, see
[Frontend icons](https://docs.typo3.org/permalink/fgtclb/academic-base:configuration-frontend-icons@main).

Of the frontend icons, three kinds are left out of the answer rather than
answered with the placeholder of an unknown icon:

-   the placeholder `default-not-found` itself, and an identifier the frontend
    registry does not know,
-   an icon whose provider does not inline an SVG file: a bitmap icon, a
    sprite icon or a font icon. Served are the icons of
    `CurrentColorSvgIconProvider` and of the core
    `\TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider`,
-   an identifier that is longer than 100 characters, holds anything but
    lowercase letters, digits, `_`, `.` and `-`, or starts with `.` or `-`.

The markup is what the provider of the icon renders, sanitised as far as that
provider sanitises. `CurrentColorSvgIconProvider` sanitises on TYPO3 v13
and v14, the inline markup of the core `SvgIconProvider` is sanitised on
TYPO3 v14 only. That is the same markup, with the same exposure, as the icon
rendered inline by a template.

## Third-party icons {#icons-licence}

The SVG icons below `Resources/Public/Icons/`, except
`Extension.svg`, are [Font Awesome Free](https://fontawesome.com)
icons by Fonticons, Inc., licensed under the [Creative Commons Attribution 4.0
International license](https://creativecommons.org/licenses/by/4.0/). The
notice `Resources/Public/Icons/LICENSE-font-awesome.txt` lists every file
with its Font Awesome name and the changes made to it.

The files are taken from version 7.3.1. They are modified: the fill colour
moved to the root element, `width` and `height` were added, and each file is
named after its purpose. Each file keeps Font Awesome's attribution comment,
which the icon provider removes from the rendered markup together with every
other comment. `Extension.svg` is the icon of the extension itself and is
not part of the set.
