Skip to content

08 Ful getting started

Roberto Ferranti edited this page Nov 3, 2026 · 9 revisions

ful: getting started

ful is the component library: form fields, selects, files, temporals, filters and tables, on top of ftl and httpc. It ships its own css, themed through --ful-* custom properties, and needs no other stylesheet and no icon fonts.

The plugin

ful installs itself on the registry through a plugin, which registers every element, the built-in loaders, the http-client component, the l10n module and the language overlay:

<script>
    ftl.registry
        .plugin(new ful.Plugin({
            language: 'it',                    // optional: BCP-47 tag or primary subtag, case-insensitive; default is the browser's language, then 'en'
            translations: { /* optional: reword built-ins or add keys */ },
            // httpClient: optional, the client every ful component fetches through
        }))
        .configure();
</script>

Without an httpClient, the plugin builds one that sends the page's csrf token and navigates to / on a 401 response. defineElement and defineModule calls can chain after plugin(...) and before configure(), and everything upgrades together when configure() runs. A defineElement there under a tag the plugin already registered replaces the plugin's class with yours, a subclass of it typically; after configure() the same call throws, since the platform defines a tag once. Modules belong there too: the custom slot templates of ful-input-file and ful-select are bound to the modules defined when the element upgrades, and keep them. Localization covers language and translations.

ful needs ftl and httpc loaded first, which the single bundle fml.iife.min.js or the ES modules take care of, and its stylesheet, ful.css (bundled in fml.css too). Getting started shows every way to load them. client-errors is the optional error reporter, loaded by one script tag of its own.

A first form

<ful-form action="/api/newsletter" method="POST">
    <ful-input name="email" required type="email" placeholder="you@example.com">
        Email
    </ful-input>
    <ful-checkbox name="privacy" required>
        I accept the privacy policy
    </ful-checkbox>
    <button type="submit">Subscribe</button>
</ful-form>
  • fields are form-associated custom elements: they participate in the inner form, expose value, required, readonly, disabled, setCustomValidity.
  • ful-form takes over the submission and runs it through an async pipeline with typed failures. See forms.
  • input-* attributes are forwarded to the inner native control, on every input-based field (ful-filter-boolean's control is a button, and forwards nothing).

What you get

Twenty-nine elements, in five families:

Area Elements Page
forms ful-form forms
fields ful-input (text, textarea, any input type), ful-checkbox, ful-radio-group, ful-select, ful-input-file, ful-input-local-date, ful-input-local-time, ful-input-instant inputs, select, files, temporals
tables ful-table, ful-pagination, ful-sorter, ful-filter-text, ful-filter-number, ful-filter-boolean, ful-filter-local-date, ful-filter-instant, ful-filter-in tables
disclosures and navigation ful-tooltip, ful-dialog, ful-drawer, ful-menu, ful-toasts, ful-tabs, ful-accordion, ful-wizard disclosures
displays and support ful-local-date, ful-instant, ful-dropdown temporals, select

Every attribute, slot and event of every one of them is in the generated Element reference. The protocols they all share, being the disabled and readonly claims, validation, the change event, the structural tags and theming, are in fields and shared protocols. The reasoning behind them is in Concepts.

A full example

a form assembled from ful fields

examples/ful/kitchen-sink.html in the repo shows every component in its normal, disabled, readonly, invalid and loading states. The other examples in examples/ful/ (select.html, table.html, files.html, temporals.html, disclosures.html, navigation.html) each focus on one area, and examples/ftl/l10n.html shows the localization.

Clone this wiki locally