Skip to main content

Upgrade to 1.0

View as Markdown

The steps below cover the changes most projects run into. Every detail, with the betas listed one by one, is in the changelog.

1.0 needs TYPO3 14, PHP 8.3 and typo3fluid/fluid 5.2 or newer.

ui:ref names are camelCase, like part names everywhere else. The rendered attribute is data-<component>-<part> with the root id as its value:

ui:ref renders no data-scope and data-part. Update CSS that selects your own parts by those attributes: [data-scope=carousel][data-part=container] becomes [data-carousel-container].

A per-item value goes into its own value argument, which also renders data-value: {ui:ref(name: 'item', value: item.value, data: refData)}. See ui:ref.

ui:useProps binds the imported props to a variable, and spreadProps takes that variable:

See ui:useProps.

controlled="{true}" becomes autoMount="{false}":

Mount it on the client with mount(), see Mount on the client.

A component accepts asChild when its template marks the target tag with {ui:asChild()}. The primitives do this already. For your own components, add it next to {ui:attributes()}:

See Composition.

ui:hydrationData is gone. Expose constants like icons or labels with a getter on the global context and read them with getGlobal(). Static markup that only your script uses can also live in the entry file.

ui:slotFilled is gone. Store the slot and test the variable, which renders the slot once:

name takes the component as you write its tag: <ui:context name="ui:dialog" as="dialogContext" />.

See Field.

ui:call escapes the text it returns. Wrap it in f:format.raw where the method returns HTML.

Recommended: rename component templates to *.fluid.html, like the primitives. typo3 fluid:analyze checks only files with that extension, which makes it a quick way to find templates that no longer parse.

0.x 1.0
mount('select', callback) mountAll('ui:select', callback)
mountControlled('dialog', id, cb) mount('ui:dialog', id, cb)
getHydrationData('carousel', id) getHydrationData('ui:carousel', id)

Every lookup takes the namespaced name, as you write the tag. A wrapper like ui:navigationMenu.root registers under ui:navigationMenu, a primitive you use directly under primitives:<name>.

Mount components with mountAll() or mount(), not with new Select(getHydrationData(...).props). The mount functions convert client props such as a Select collection into the objects the machine expects, and the raw hydration data fails with findMany is not a function. See Mounting.

See ComponentHydrator.

The constructor stores the props, init() builds the hydrator, machine and api. Call init() before you read api or hydrator. A class that overrides init() returns this, so a mount callback can return new Accordion(props).init().

Optional: jramke/fluid-types types the props of mountAll() and mount() per component. See Generating TypeScript types.

Add the output to your tsconfig.json with a glob. A plain "types.generated" entry reads as a file name because of the dot, and TypeScript skips the folder: