Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Fluid Detected

Fluid Detected

Next Gen Templating in TYPO3 14

TYPO3 14 introduces important new features in Fluid that are relevant for both integrators and frontend developers. Combined with modern frontend tooling, they can transform how we approach templating in TYPO3 projects.

This talk brings together new ViewHelpers, Fluid Components, and Vite, showing how these pieces fit into a more streamlined and maintainable frontend workflow. As a result, TYPO3 becomes easier to approach for frontend developers by using familiar concepts from modern frontend stacks.

#t3dd #t3dd26 #typo3 #fluid

Avatar for Simon Praetorius

Simon Praetorius

August 06, 2026

More Decks by Simon Praetorius

Other Decks in Technology

Transcript

  1. Fluid Detected Simon Praetorius We will cover ✦ PAGEVIEW object

    ✦ new ViewHelpers ✦ Fluid components ✦ frontend assets with Vite fi ✦ … and how they t together
  2. Fluid Detected – Project Setup Sitepackage Extension packages/devdays26/ ✦ composer.json

    ✦ ext_emconf.php setup: ddev composer req praetorius/devdays26 ddev typo3 extension:setup Simon Praetorius
  3. Fluid Detected – Project Setup SiteSet Con guration/Sets/ ✦ DevDays26/

    ✦ config.yaml ✦ page.tsconfig fi ✦ setup.typoscript Simon Praetorius
  4. Fluid Detected – Project Setup Backend Layout page.tsconfig: mod. eb_layout.BackendLayouts.default

    { title = Default config.backend_layout { colCount = 1 rowCount = 2 rows { 1.columns.1 { w name = Hero Simon Praetorius
  5. Fluid Detected – Project Setup Simon Praetorius Backend Layout page.tsconfig:

    rows { 1.columns.1 { name = Hero identifier = hero colPos = 100 allowedConten } T t 2.columns.1 { ypes = devdays26_hero
  6. Fluid Detected – Project Setup Simon Praetorius Backend Layout page.tsconfig:

    2.columns.1 { name = Content identifier = ain colPos = 0 allowedConten } } T t m } ypes = header, text, textpic
  7. Fluid Detected – Project Setup Simon Praetorius Page Rendering setup.typoscript:

    page = PAGE page { 10 = PAGEVI 10 { paths.10 = EX :devdays26/Resources/Private/ emplates/ dataProcessing { enu ainMenu T W m E m 10.as = T 10 =
  8. Fluid Detected – Project Setup Simon Praetorius Content Rendering setup.typoscript:

    lib.contentElement = FLUIDT PLA lib.contentElement { templateRootPaths { 10 = EX :devdays26/Resources/Private/ emplates/Content/ } templateName.if pty.cObject = templateName.if pty.cObject { X T T E E T T M E m m E E T field = CType
  9. Fluid Detected – Project Setup Simon Praetorius Content Rendering setup.typoscript:

    templateName.if pty.cObject = templateName.if pty.cObject { X field = CType required = 1 case = uppercamelcase } dataProcessing.10 = record-transformation T E T m m E E }
  10. Fluid Detected – Project Setup Simon Praetorius Content Rendering setup.typoscript:

    templateName.if pty.cObject = templateName.if pty.cObject { X field = CType required = 1 case = uppercamelcase } dataProcessing.10 = record-transformation T E T m m E E }
  11. Fluid Detected – Project Setup Content Rendering setup.typoscript: tt_content =

    CASE tt_content.default =< lib.contentElement Simon Praetorius
  12. Fluid Detected – Project Setup Template Folder Structure Resources/Private/Templates/ ✦

    Content/ ✦ Header.fluid.html ✦ Text.fluid.html ✦ Textpic.fluid.html ✦ Pages/ ✦ Default.fluid.html Simon Praetorius
  13. Fluid Detected – Project Setup Simon Praetorius Fluid Components ComponentCollections.php:

    return [ 'Praetorius\\DevDays26\\Components' => [ 'templatePaths' => [ 10 => 'EX :devdays26/Resources/Private/Components/', ], ], T ];
  14. Fluid Detected – Project Setup Global Namespace Namespaces.php: return [

    'dd26' => ['Praetorius\\DevDays26\\Components'], ]; Simon Praetorius
  15. Fluid Detected – Project Setup Component Folder Structure Resources/Private/Components/ ✦

    Atom/ ✦ Molecule/ ✦ Gallery/ ✦ Gallery.css ✦ Gallery.fluid.html ✦ Gallery.js ✦ Organism/ Simon Praetorius
  16. Fluid Detected – Project Setup Vite project root ✦ package.json

    / package-lock.json ✦ vite.config.js packages/devdays26/ ✦ Configuration/ViteEntrypoints.json ✦ Resources/Private/Assets/ ✦ Components.entry.js ✦ Main.entry.css Simon Praetorius
  17. Fluid Detected – Project Setup Setup Vite TYPO3 extension: ddev

    composer req praetorius/vite-asset-collector NPM packages: ddev np i --save-dev vite vite-plugin-typo3 DDEV add-on: m ddev add-on get s2b/ddev-vite-sidecar Simon Praetorius
  18. Simon Praetorius Con gure Vite vite.config.js: port { defineConfig }

    fro port typo3 fro "vite"; "vite-plugin-typo3"; export default defineConfig({ plugins: [typo3({ aliases: "EXT" })], }); use "type": odule" m m m fi m in package.json m i i Fluid Detected – Project Setup
  19. Fluid Detected – Project Setup Simon Praetorius Con gure Vite

    Configuration/ViteEntrypoints.json: [ "../Resources/Private/Assets/ ain.entry.css", "../Resources/Private/Assets/Components.entry.js" M fi ]
  20. Fluid Detected – Project Setup Collect Assets m m m

    m m i i i i i Resources/Private/Assets/Main.entry.css: @ port "Css/Variables.css"; @ port "Css/Fonts.css"; @ port "Css/Reset.css"; @ port "Css/Base.css"; @ port "Css/Utilities.css"; Simon Praetorius
  21. Fluid Detected – Project Setup Simon Praetorius Embed Assets Resources/Private/Templates/Pages/Default.fluid.html:

    {namespace vite=Praetorius\ViteAssetCollector\ViewHelpers} <vite:asset entry="EX :devdays26/Resources/Private/Assets/ ain.entry.css" /> <vite:asset entry="EX :devdays26/Resources/Private/Assets/ T T M Components.entry.js" />
  22. Fluid Detected – Project Setup Build Assets run dev server:

    ddev vite build assets (deployment): m np exec vite build Simon Praetorius
  23. Fluid Detected – Project Setup Simon Praetorius Folder Structure Resources/Private/…

    Assets/ Components/ Templates/ ✦ Css/ ✦ Atom/ ✦ Content/ ✦ Fonts/ ✦ Molecule/ ✦ Pages/ ✦ JavaScript/ ✦ Organism/ Frontend Integration
  24. Fluid Detected – Frontend Simon Praetorius Global vs. Scoped Assets/

    Components/ ✦ CSS framework ✦ Fluid components (reset, base, utilities, variables/tokens) ✦ JavaScript utilities ✦ web fonts (API + implementation) ✦ (manually) scoped CSS ✦ component JavaScript
  25. Fluid Detected – Frontend Simon Praetorius Gallery Component (API) Components/Molecule/Gallery/Gallery.fluid.html:

    <f:argument name=" ages" type="TYPO3\C S M m i /> \Core\Resource\FileInterface[]"
  26. Fluid Detected – Frontend Simon Praetorius Gallery Component (HTML) Components/Molecule/Gallery/Gallery.fluid.html:

    <div class="mGallery s <div class="s per" data-component="mGallery"> per-wrapper"> <f:for each="{ ages}" as=" <div class="s per-slide"> <dd26:ato . age age"> age="{ age}" lazy="{true}" class="mGallery__ </div> i m w i m i m i m i i w i m m w i i m i w </f:for> dth="800" age" />
  27. Fluid Detected – Frontend Simon Praetorius Gallery Component (HTML) Components/Molecule/Gallery/Gallery.fluid.html:

    <div class="mGallery s <div class="s per" data-component="mGallery"> per-wrapper"> <f:for each="{ ages}" as=" <div class="s per-slide"> <dd26:ato . age age"> age="{ age}" lazy="{true}" class="mGallery__ </div> dth="800" age" /> scoping i m w i m i m i m i i w i m m w i i m i w </f:for>
  28. Simon Praetorius Gallery Component (HTML) Components/Molecule/Gallery/Gallery.fluid.html: <div class="mGallery s <div

    class="s per" data-component="mGallery"> per-wrapper"> <f:for each="{ ages}" as=" <div class="s per-slide"> <dd26:ato . age age"> age="{ age}" lazy="{true}" class="mGallery__ age Component!? </div> i m w i m i m i m i i w i m m w i i m i w </f:for> m I Fluid Detected – Frontend dth="800" age" />
  29. Fluid Detected – Frontend Simon Praetorius Image Component (API) Components/Atom/Image/Image.fluid.html:

    <f:argument name=" type="TYPO3\C age" \Core\Resource\FileInterface" /> <f:argument name=" dth" type="integer" optional="{true}" /> <f:argument name="lazy" type="boolean" optional="{true}" default="{false}" /> <f:argument name="class" m i i w S M type="string" optional="{true}" />
  30. Fluid Detected – Frontend Simon Praetorius Image Component (HTML) Components/Atom/Image/Image.fluid.html:

    <f: age age="{ age}" dth="{ dth}" loading="{f:if(condition: lazy, then: 'lazy')}" class="{class}" m i i w m i m i i w />
  31. Simon Praetorius Gallery Component (HTML) Components/Molecule/Gallery/Gallery.fluid.html: <div class="mGallery s <div

    class="s per" data-component="mGallery"> per-wrapper"> <f:for each="{ ages}" as=" <div class="s per-slide"> <dd26:ato . age age"> age="{ age}" lazy="{true}" class="mGallery__ i m w i i m i m i i w i m m w i i m i w </f:for> m ✔ age Component </div> m I Fluid Detected – Frontend dth="800" age" />
  32. Fluid Detected – Frontend Simon Praetorius Gallery Component (CSS) Components/Molecule/Gallery/Gallery.css:

    . Gallery { cursor: grab; } scoping . Gallery__ age { dth: 100 ; height: auto; m % i i w m m }
  33. Fluid Detected – Frontend Simon Praetorius Gallery Component (JS) Components/Molecule/Gallery/Gallery.js:

    async function gallery(el) { port("s const per/css"); per = (await ne port("s per")). per(el); } i w S i w m i i w i w S i w S w m i registerComponent("mGallery", gallery); per;
  34. Fluid Detected – Frontend Simon Praetorius Gallery Component (JS) Components/Molecule/Gallery/Gallery.js:

    async function gallery(el) { port("s const per/css"); per = (await ne per(el); port("s per")). code splitting } i w S i w m i i w i w S i w S w m i registerComponent("mGallery", gallery); per;
  35. Fluid Detected – Frontend Simon Praetorius Gallery Component (JS) Components/Molecule/Gallery/Gallery.js:

    async function gallery(el) { port("s const per/css"); per = (await ne port("s per")). per(el); } i w S i w m i i w i w S i w S w m i registerComponent("mGallery", gallery); per;
  36. Simon Praetorius Component Registry (Utility) registry & initializer (DOMContentLoaded) Gallery.fluid.html:

    <div data-component="mGallery"> Gallery.js: port { registerComponent } fro "../../../Assets/JavaScript/Utilities"; m registerComponent("mGallery", gallery); m i Fluid Detected – Frontend
  37. Fluid Detected – Integration Simon Praetorius Page Template Templates/Pages/Default.fluid.html: <header>

    <dd26:organis .header enu="{ ainMenu}" /> <f:render.contentArea contentArea="{content.hero}" /> </header> <main> <f:render.contentArea contentArea="{content. ain}" /> </ ain> m m m m m m <footer><dd26:organis .footer /></footer>
  38. Fluid Detected – Integration Simon Praetorius Page Template Templates/Pages/Default.fluid.html: <header>

    <dd26:organis .header enu="{ ainMenu}" /> <f:render.contentArea contentArea="{content.hero}" /> </header> ne <main> ViewHelper <f:render.contentArea contentArea="{content. ain}" /> </ ain> m m m m m m w <footer><dd26:organis .footer /></footer>
  39. Fluid Detected – Integration Simon Praetorius Page Template Templates/Pages/Default.fluid.html: <header>

    <dd26:organis .header enu="{ ainMenu}" /> <f:render.contentArea contentArea="{content.hero}" /> </header> render components <main> <f:render.contentArea contentArea="{content. ain}" /> </ ain> m m m m m m <footer><dd26:organis .footer /></footer>
  40. Fluid Detected – Integration Simon Praetorius Textpic Template Templates/Content/Textpic.fluid.html: <dd26:ato

    .headline header="{f:render.text(record: record, field: 'header')}" position="{record.header_position}" /> <dd26:ato .text> <f:render.text record="{record}" field="bodytext" /> </dd26:ato .text> m ages="{record. i m i m m m m <dd26: olecule.gallery age}" />
  41. Fluid Detected – Integration Simon Praetorius Textpic Template Templates/Content/Textpic.fluid.html: <dd26:ato

    .headline header="{f:render.text(record: record, field: 'header')}" position="{record.header_position}" /> ne ViewHelper <dd26:ato .text> <f:render.text record="{record}" field="bodytext" /> </dd26:ato .text> m ages="{record. i m i m m m m w <dd26: olecule.gallery age}" />
  42. Fluid Detected – Integration Simon Praetorius Textpic Template Templates/Content/Textpic.fluid.html: <dd26:ato

    .headline header="{f:render.text(record: record, field: 'header')}" position="{record.header_position}" /> <dd26:ato .text> <f:render.text record="{record}" field="bodytext" /> render Gallery component </dd26:ato .text> m ages="{record. i m i m m m m <dd26: olecule.gallery age}" />
  43. Fluid Detected Simon Praetorius Demo Project on GitHub ✦ PAGEVIEW

    ✦ integration ViewHelpers ✦ Fluid components ✦ SrcsetViewHelper (responsive images) ✦ frontend assets with Vite ✦ Content Blocks + Visual Editor