pixelegg / pxe-counter
Animated number counter content element for TYPO3: counts up when scrolled into view, locale-aware, accessible, no dependencies. With a backend overview of all counters.
Package info
github.com/pixelegg/pxe-counter
Type:typo3-cms-extension
pkg:composer/pixelegg/pxe-counter
Requires
- php: ^8.2 || ^8.3 || ^8.4
- ext-intl: *
- typo3/cms-backend: ^13.4 || ^14.0
- typo3/cms-core: ^13.4 || ^14.0
- typo3/cms-fluid: ^13.4 || ^14.0
- typo3/cms-fluid-styled-content: ^13.4 || ^14.0
- typo3/cms-frontend: ^13.4 || ^14.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.95
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^10.5 || ^11.5 || ^12.0
- saschaegerer/phpstan-typo3: ^2.1 || ^3.0
- ssch/typo3-rector: ^3.0
- typo3/coding-standards: ^0.8 || ^0.9
- typo3/testing-framework: ^8.2 || ^9.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
A content element that shows a number counting up from a start to an end value when it scrolls into view ("1,200 happy clients", "98 %", "€ 4.5 M"). The final value is rendered server-side and formatted for the site language, so it is correct without JavaScript and for screen readers; a small dependency-free script (3 KB, no jQuery) adds the animation. CSS and JS are loaded only on pages that use the element. A backend module Counter (Content > Counter in TYPO3 14, Web > Counter in 13.4) lists every counter of the installation and flags those that will not animate.
Counters on a demo page with a minimal theme: the default layout in the first row, the layout variants Accent, Inline and Bold below.
Requirements
| TYPO3 | 13.4 LTS or 14 |
| PHP | 8.2, 8.3 or 8.4 with ext-intl (required by TYPO3 anyway) |
| Core extension | fluid_styled_content (the element renders through lib.contentElement) |
Installation
composer require pixelegg/pxe-counter
Then activate the TypoScript in one of two ways (not both):
A. Site set (sites configured entirely through sets)
Site Management > Sites > your site > Sets: add Counter (animated number)
(pixelegg/counter). Settings become editable under Site Management > Settings.
Note: TYPO3 13/14 only load the TypoScript of site sets when the root page has
no sys_template record. If your site still has a root template, use B.
B. Static template Web > Template > your root template > Includes: add Counter (animated number). Settings are TypoScript constants (see below).
Both load the same Configuration/TypoScript/setup.typoscript. Clear the caches afterwards.
Non-composer installations install the extension from the TER and continue with step A or B.
Usage
Add the content element Counter (animated number) (Zähler (animierte Zahl) in German). It appears in the Typical page content tab of the new-content wizard (TYPO3 13.4 and 14). Fields:
The element in the new content element wizard (TYPO3 14, tab "Typical page content").
| Field | Meaning | Default |
|---|---|---|
| Start value | Number the animation starts from; decimals allowed (up to two places stored) | 0 |
| End value | Number that is finally shown (also without JavaScript), e.g. 4.5 |
0 |
| Prefix | Short text before the number, e.g. € or + |
– |
| Suffix | Short text after the number, e.g. % or k |
– |
| Caption | Text below the number | – |
| Decimal places | 0–4 (set 1 for 4.5) |
0 |
| Group thousands | Thousands separator according to the site language (1,000 / 1.000 / 1 000) |
on |
| Duration | Animation length in seconds | 2 |
| Delay | Pause before the animation starts, in seconds | 0 |
| Easing | ease-out (fast → slow), linear, ease-in-out | ease-out |
| Layout | Default, Accent (primary colour), Inline (number and caption side by side), Bold | Default |
Editing form, tab "General".
Header, header type, subheader and header link (core Headers palette) as well as frame class and spacing from the Appearance tab apply like for any other content element.
Number formatting
Grouping and decimal separators follow the locale of the site language (de_DE → 1.234,5,
en_US → 1,234.5, fr_FR → 1 234,5), both server-side (NumberFormatter) and during
the animation (Intl.NumberFormat). Nothing is hard-coded.
TypoScript constants / site settings
| Constant | Default | Purpose |
|---|---|---|
plugin.tx_pxecounter.settings.includeAssetsGlobally |
0 |
0: CSS/JS are added only on pages with a counter (<f:asset.css> / <f:asset.script>, deferred). 1: the files are registered through page.includeCSS / page.includeJSFooter on every page. Use 1 with themes that concatenate or compress those lists (e.g. t3sbootstrap), where AssetCollector assets would bypass the bundle. |
plugin.tx_pxecounter.view.templateRootPath |
EXT:pxe_counter/Resources/Private/Templates/ContentElements/ |
Template directory (index 10) |
plugin.tx_pxecounter.view.partialRootPath |
EXT:pxe_counter/Resources/Private/Partials/ContentElements/ |
Partial directory (index 10) |
plugin.tx_pxecounter.view.layoutRootPath |
EXT:pxe_counter/Resources/Private/Layouts/ContentElements/ |
Layout directory (index 10) |
With the site set the same keys appear in Site Management > Settings, category Counter (animated number).
Overriding the template
Keep index 10 for the extension and add your own directory at index 20:
tt_content.pxe_counter {
templateRootPaths.20 = EXT:my_sitepackage/Resources/Private/Templates/ContentElements/
}
Copy Resources/Private/Templates/ContentElements/Counter.html there and adjust it. The template
receives:
{counter}fromPixelegg\PxeCounter\DataProcessing\CounterProcessor:from,to,fromFormatted,toFormatted,decimals,grouping,duration,delay,easing,layout,prefix,suffix,label,locale(BCP 47 tag),animate{flexform}with the raw FlexForm values{data}with thett_contentrow,{settings}with the TypoScript settings
Keep the pxe-counter, pxe-counter__number and pxe-counter__value classes and the data-*
attributes: counter.js relies on them. Layout variants are plain class hooks
(layout-default, layout-1, layout-2, layout-3) on the element, styled in
Resources/Public/Css/counter.css; override the CSS in your theme or replace the file via your
own template.
Accessibility and behaviour without JavaScript
- The HTML always contains the final, formatted number. Without JavaScript the number is simply shown.
- While counting, the script hides the changing digits from assistive technology
(
aria-hidden) and offers a visually hidden copy of the final value instead. Noaria-liveregion, so nothing is announced per frame. When the animation ends the original markup is restored. prefers-reduced-motion: reducedisables the animation; the final value is shown directly.- The animated value keeps the width of the final number, so surrounding content does not shift while counting.
- Colours and fonts inherit from the site; the "Accent" layout uses
--bs-primarywith a fallback.
Backend module
Content > Counter (TYPO3 14) / Web > Counter (13.4) lists all Counter elements of the installation (also hidden ones and translations) with page, start → end, easing and a status: OK, or Won't animate when the start equals the end. Each row links to the element and to its page. Available to every backend user with access to the module; English and German.
The backend module. German interface: screenshot.
If the optional dashboard extension pxe_hub is installed, the module is hidden from the
module menu and reached through the hub instead. Nothing else changes.
Development
composer install composer ci:cs # php-cs-fixer (typo3/coding-standards), dry run composer ci:stan # PHPStan level 8 composer ci:rector # rector, dry run composer ci:test # unit tests composer ci:test:functional # functional tests (sqlite)
CI runs the suite for TYPO3 13.4 (PHP 8.2–8.4) and TYPO3 14 (PHP 8.3–8.4); see
.github/workflows/ci.yml. Tags vX.Y.Z are published to the TER by
.github/workflows/publish-ter.yml when the repository secret TYPO3_API_TOKEN is set.
Changelog
See CHANGELOG.md.
License
GPL-2.0-or-later, see LICENSE.txt. Made by pixelegg.