PHPackages                             lin3s/front-foundation - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. lin3s/front-foundation

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

lin3s/front-foundation
======================

Library that provides a sort of commonly used front-end components in LIN3S projects

v0.19.3(7y ago)03.7k2[2 issues](https://github.com/LIN3S/FrontFoundation/issues)MITJavaScript

Since Sep 29Pushed 2y ago3 watchersCompare

[ Source](https://github.com/LIN3S/FrontFoundation)[ Packagist](https://packagist.org/packages/lin3s/front-foundation)[ RSS](/packages/lin3s-front-foundation/feed)WikiDiscussions master Synced yesterday

READMEChangelog (10)DependenciesVersions (37)Used By (0)

LIN3S Front Foundation
======================

[](#lin3s-front-foundation)

> Base CSS and JS files for building views in LIN3S way.

Installation
------------

[](#installation)

The recommended and the most suitable way to install is through *Yarn*:

```
$ yarn add lin3s-front-foundation
```

or alternatively through *NPM*:

```
$ npm install --save lin3s-front-foundation
```

---

---

Usage - Available features
--------------------------

[](#usage---available-features)

### Async

[](#async)

This package will provide all asynchronous related implementations. For instance, Promise related ones.

#### Async.cancelablePromise( promise )

[](#asynccancelablepromise-promise-)

This method will wrap a Promise object and provide a cancel() method for canceling the inner Promise. We will access the original promise throught the promise property.

```
import {Async} from 'lin3s-front-foundation';

const aPromise = new Promise((resolve, reject) => {
  // ...
});

const aCancelablePromise = Async.cancelablePromise(aPromise);

aCancelablePromise.promise.then(resolvedObject => {
  // ...
});

aCancelablePromise.cancel();
// aCancelablePromise.promise has been rejected right after calling the cancel() method.
```

---

### Browser

[](#browser)

This package will provide all browser related implementations.

#### Browser.isIE11()

[](#browserisie11)

This method will tell us if the browser is Internet Explorer 11.

```
import {Browser} from 'lin3s-front-foundation';

const isIE11 = Browser.isIE11();
```

---

### Dom

[](#dom)

This package will provide all Dom related implementations.

```
import {Dom} from 'lin3s-front-foundation';

const currentHtmlLang = Dom.getHtmlLang();

console.log(currentHtmlLang);
```

#### Dom.getHtmlLang()

[](#domgethtmllang)

This method will return the html tag's *lang* attribute.

#### Dom.loadScript( scriptPath )

[](#domloadscript-scriptpath-)

This method will load an script by the provided scriptPath and return us a Promise object. This promise will be resolved one the script has been loaded.

```
import {Dom} from 'lin3s-front-foundation';

const scriptPath = 'https://yourdomain.com/script-path.js';

const scriptLoadPromise = Dom.loadScript(scriptPath);

scriptLoadPromise.then(() => {
  // Our script has been loaded!
});
```

#### Dom.injectScript( scriptCode, domNode = document.body )

[](#dominjectscript-scriptcode-domnode--documentbody-)

This method will inject the specified *scriptCode* at the passed *domNode*. *domNode* will be the document's body by default. Provided *scriptCode* will be wrapped with an [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE)

```
import {Dom} from 'lin3s-front-foundation';

const
  mainDomNode = document.querySelector('.main'),
  testScriptA = `console.log('This is the injected script A');`,
  testScriptB = `console.log('This is the injected script B');`;

Dom.injectScript(testScriptA);
Dom.injectScript(testScriptB, mainDomNode);
```

#### Dom.waitImagesLoadInDomNode( domNode )

[](#domwaitimagesloadindomnode-domnode-)

This method will return us a Promise object that will be resolved once all the images contained in the provided domNode have been loaded.

```
import {Dom} from 'lin3s-front-foundation';

const imagesCollection = document.querySelector('.images__collection');

const imagesLoadPromise = Dom.waitImagesLoadInDomNode(imagesCollection);

imagesLoadPromise.then(() => {
  // All images have been loaded!
});
```

#### Dom.scrollToElement( selector, {duration = 500, offset = 0, callback = null} )

[](#domscrolltoelement-selector-duration--500-offset--0-callback--null-)

This method will scroll to the given element's positions minus offset in the given duration (in milliseconds). A callback can be provided that will trigger once the animation has finished.

```
import {Dom} from 'lin3s-front-foundation';

const callback = () => console.log('Scroll to element done!');

Dom.scrollToElement('.some-selector', {duration: 2000, offset: 10, callback});
```

### Dom - Utilities / Helpers

[](#dom---utilities--helpers)

#### Dom.isDomNodeDescendantOfDomNode( needleDomNode, mainDomNode )

[](#domisdomnodedescendantofdomnode-needledomnode-maindomnode-)

This method will return true if the passed `needleDomNode` y a descendant of the `mainDomNode`.

#### Dom.getDomNodeIndex( domNode, selector = null )

[](#domgetdomnodeindex-domnode-selector--null-)

This method will return the index of the provided `domNode`, optinally filtered by a css selector. It is a native alternative to the jQuery's [`.index()`](https://api.jquery.com/index/) method.

#### Dom.removeDomNodes( domNodes )

[](#domremovedomnodes-domnodes-)

This method will remove the passed `domNodes` from their parents. It will work with a single node as well. It is a native alternative to the jQuery's [`.remove()`](https://api.jquery.com/remove/) method.

#### Dom.addSelectorFilteredEventListener( domNode, eventName, selector, event =&gt; {} )

[](#domaddselectorfilteredeventlistener-domnode-eventname-selector-event---)

This method will add an event listener for the `eventName` to the passed `domNode`, filtering the event.target with the defined `selector`. It is a native alternative to the jQuery's [`.on(eventName, selector, callback)`](http://api.jquery.com/on/) method when filtering it's targets by a selector.

#### Dom.dispatchNativeEvent( domNode, eventName )

[](#domdispatchnativeevent-domnode-eventname-)

This method will dispatch a DOMElement native event. It's a native alternative to the jQuery's [`.trigger(eventName)`](http://api.jquery.com/trigger/) method.

#### Dom.scrollToElement( selector, {duration = 500, offset = 0, callback = null} )

[](#domscrolltoelement-selector-duration--500-offset--0-callback--null--1)

This method will help us scrolling to a document node's position. It allows defining a duration (default 500ms), an offset (default 0) and a complete callback (default null).

```
import {Dom} from 'lin3s-front-foundation';

const links = document.querySelectorAll('.menu__list .menu__link');

const handleClick = event => Dom.scrollToElement(event.target.hash, {duration: 250, offset: 10});

Array.from(links, link => {
  link.addEventListener('click', handleClick, false);
});
```

---

### Cookies

[](#cookies)

This package will provide all `document.cookie` related implementations.

#### Cookies.read

[](#cookiesread)

This method will return the value of a cookie by its name.

```
import {Cookies} from 'lin3s-front-foundation';

const cookieValue = Cookies.read('some-name');
```

#### Cookies.write

[](#cookieswrite)

This method will write a cookie. Accepts an object with names parameters for name, value, expiration, domain and path.

```
import {Cookies} from 'lin3s-front-foundation';

Cookies.write({
  name: 'some-name',
  value: 'my value',
  expiration: 3600000, // 1 hour in milliseconds
  domain: 'example.com',
  path: '/'
});
```

The list of the available parameters, their type and default values are as follows:

ParameterTypeRequiredDefault valuenamestringyes-valuestringno''expirationint (milliseconds)no\*domainstringnolocation.hostnamepathstringno/\* It will set cookie expiration to 'Session'

#### Cookies - EventBus events

[](#cookies---eventbus-events)

`Cookies.write` will publish `CookieWrittenEvent` through the EventBus. We will subscribe to this event using some exported helper methods:

```
import {EventBus} from 'lin3s-front-foundation';

EventBus.onCookieWritten(({cookie}) => {
  const myCookieName = cookie.name;
  const myCookieValue = cookie.value;
});
```

---

---

Usage - Available UI components
-------------------------------

[](#usage---available-ui-components)

### GMap

[](#gmap)

This component will provide all the necessary implementations for displaying a Google Map, setting it's markers, setting a clusterer, use the Google Map geocoding feature and displaying the MarkerDetail view.

#### GMap - Styles

[](#gmap---styles)

The GMap component comes with some default styles. You must include them in order to correctly render it.

```
@import './node_modules/lin3s-front-foundation/dist/scss/ui/components/gmap';
@import './node_modules/lin3s-front-foundation/dist/scss/ui/components/gmap-marker-detail';
```

#### GMap - Basic setup

[](#gmap---basic-setup)

In order to setup the GMap component, we will define every required parameter while including the twig template. It will automatically fetch the needed js files and will init the Google Maps map instance.

The list of the available parameters, their type and default values are as follows:

ParameterTypeRequiredDefault valuegmap\_api\_keystringyes-gmap\_center\_latfloatyes-gmap\_center\_lngfloatyes-gmap\_initial\_zoomintno8gmap\_max\_zoomintno12gmap\_marker\_default\_pathstringyes-gmap\_marker\_selected\_pathstringyes-gmap\_marker\_group\_pathstringyes-gmap\_marker\_widthintyes-gmap\_marker\_heightintyes-gmap\_cluster\_enabledintno1 \[0,1\]gmap\_cluster\_text\_offset\_xintno0gmap\_cluster\_text\_offset\_yintno0gmap\_cluster\_text\_colorstringno'#ffffff'gmap\_cluster\_text\_sizeintno18gmap\_stylestringno[view](https://github.com/LIN3S/FrontFoundation/blob/master/src/templates/twig/components/gmap.html.twig#L26)\*\*\*\* In order to generate the Google Map custom styles, we could use any available tool. For instance the [snazzy maps](https://snazzymaps.com/)online platform.

The marker images will be required to be served both on *.png* and *.svg* formats.

The marker paths must be defined without the file extensions, as the GMap component will get the *.png* or *.svg* files based on the client browser.

This is a basic setup example:

```
{% include '@lin3s_front_foundation/components/gmap.html.twig' with {
    gmap_api_key: 'AIzaSyDQaCE_7C5iAmpwr_y1C1DHbtZsqag74Sk',
    gmap_center_lat: '43.2631394',
    gmap_center_lng: '-2.9275847',
    gmap_initial_zoom: 12,
    gmap_max_zoom: 16,
    gmap_marker_default_path: '/images/gmap/marker-default',
    gmap_marker_selected_path: '/images/gmap/marker-selected',
    gmap_marker_group_path: '/images/gmap/marker-group',
    gmap_marker_width: 40,
    gmap_marker_height: 60,
    gmap_cluster_enabled: 1,
    gmap_cluster_text_size: 14,
    gmap_cluster_text_color: '#222222'
} %}
```

#### GMap - JS API

[](#gmap---js-api)

These are the mostly used methods available on the GMap component's instance.

NameParametersReturned valueDescriptionsetCenterOffsets{
 x: 0,
 y: 0
 }undefined (void)This method will set the instance's center's offset (in pixels)setMarkersmarkers: \[{
 id: 0,
 lat: 43.2631394,
 lng: -2.9275847,
 // your properties...
},
 //...
\]undefined (void)This method will display the passed markers on the map. It will generate the clusters automatically.

 Each marker object must, at least, have the *lat*, *lng* and *id* properties.showMarkerDetailViewmarkerId, markerDetailHtmlContentundefined (void)This method will render and display the passed markerDetailHtmlContent centered on the correspondingn marker.hideMarkerDetailView-undefined (void)This method will hide the currently visible marker detail view.geocodeAddressaddress: Stringundefined (void)This method will geocode the passed address (Address, town, ZIP code, city...) and center the map on the result's location.

 If no result matches the passed address, it will publish an event through the EventBus.resetMapZoomAndCenterToDefault-undefined (void)This method will reset the instance's center and zoom to the default values.#### GMap - EventBus events

[](#gmap---eventbus-events)

Each GMap instance will publish these events through the EventBus. We will subscribe to these events using some exported helper methods:

```
import {EventBus} from 'lin3s-front-foundation';

const domNode = document.querySelector('.my-map');

EventBus.onGMapInitialized(domNode, gmapInitializedEvent => {
  const gmapInstance = gmapInitializedEvent.gmapInstance;
});

EventBus.onGMapGeocode(domNode, gmapGeocodeEvent => {
  console.log(gmapGeocodeEvent.status);
  console.log(gmapGeocodeEvent.results);
});

EventBus.onGMapMarkerSelected(domNode, gmapMarkerSelectedEvent => {
  const selectedMarker = gmapMarkerSelectedEvent.marker;
});
```

TypePropertiesGMapInitializedEventgmapInstance: GMapGMapMarkerSelectedEventgmapInstance: GMap
marker: Your marker object representationGMapGeocodeEventgmapInstance: GMap
status: response status
results: geociding results#### GMap - Advanced features

[](#gmap---advanced-features)

If we need to work with the initialized GMap component instance, we must subscribe to the GMapInitializedEvent, that will be published through the event-bus once the gmap component has been initialized.

```
import {EventBus} from 'lin3s-front-foundation';

const domNode = document.querySelector('.my-map');

EventBus.onGMapInitialized(domNode, gmapInitializedEvent => {
  const gmapInstance = gmapInitializedEvent.gmapInstance;
  // whatever...
});
```

We will set the GMap component's markers calling the *setMarkers(markers)* method.

If we want to use the built-in geocoding feature, we will call the *geocodeAddress(address)* of the GMap instance.

The GMap component also comes with methods for displaying/hiding the marker detail view ( *showMarkerDetailView(markerId, markerDetailContentHtml)* and *hideMarkerDetailView()*).

This is a complete example of the component's features:

```
import {EventBus} from 'lin3s-front-foundation';

class GMapTest {
  constructor(domNode) {
    this.domNode = domNode;

    EventBus.onGMapInitialized(this.domNode, gmapInitializedEvent => {
      const gmapInstance = gmapInitializedEvent.gmap;
      this.setupMarkers();
      this.init();
    });
  }

  setupMarkers() {
    const markers = [{
      id: 0,
      lat: 43.2631394,
      lng: -2.9275847
    }];

    this.gmapInstance.setMarkers(markers);
  }

  init() {
    this.filterInput = document.querySelector('.my-input-class');
    this.filterInput.addEventListener('input', () => {
      this.gmapInstance.geocodeAddress(this.filterInput.value);
    });

    EventBus.onGMapGeocode(this.domNode, gmapGeocodeEvent => {
      console.log(gmapGeocodeEvent.status);
      console.log(gmapGeocodeEvent.results);
    });

    EventBus.onGMapMarkerSelected(this.domNode, gmapMarkerSelectedEvent => {
      this.onMarkerSelected(gmapMarkerSelectedEvent.marker);
    });
  }

  onMarkerSelected(marker) {
    if (marker === undefined) {
      this.gmapInstance.hideMarkerDetailView();
    } else {
      this.gmapInstance.showMarkerDetailView(
        marker.id,
        `This is the marker detail's inner html content
         Marker lat: ${marker.lat}
         Marker lng: ${marker.lng}`
      );
    }
  }
}

onDomReady(() => {
  new GMapTest();
});
```

---

### FormGroupInput

[](#formgroupinput)

The component is composed by the FormLabel, FormInput and the FormError atoms.

#### FormGroupInput - Styles

[](#formgroupinput---styles)

The FormGroupInput component and it's associated atoms come with some default styles. You must include them in order to correctly render them.

```
@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-label';
@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-error';
@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-input';
@import './node_modules/lin3s-front-foundation/dist/scss/ui/components/form-group-input';
```

#### FormGroupInput - Basic setup

[](#formgroupinput---basic-setup)

In order to setup the FormGroupInput component, we will define every required parameter while including the twig template.

The list of the available parameters, their type and default values are as follows:

ParameterTypeRequiredDefault valueinput\_idstringyesinput\_namestringnonullinput\_valuestringnonullinput\_requiredintno0input\_validateintno0input\_validation\_patternstringno''input\_validation\_typestringno''input\_typestringno'text'input\_placeholderstringyes-input\_label\_class\_namestringnonullinput\_label\_modifiersstringnonullinput\_label\_contenthtmlnonullinput\_errorsarray
{
 content: string\*,
 modifiers: string
}nonullinput\_class\_namestringnonullinput\_modifiersstringnonullinput\_spinnerintno0This is a common setup example:

```
{% include '@lin3s_front_foundation/components/form_group_input.html.twig' with {
    input_id: 'my-form-user-name',
    input_required: 1,
    input_validate: 1,
    input_validation_type: 'phone',
    input_type: 'text',
    input_placeholder: 'Enter some data...',
    input_label_content: 'Your user name',
    input_errors: [{
        content: 'This field is required',
        modifiers: 'form-error--not-filled'
    }, {
        content: 'Entered phone is not a 9 digit valid phone',
        modifiers: 'form-error--not-valid'
    }],
    input_spinner: 1
} %}
```

---

### FormGroupSelect

[](#formgroupselect)

This component and it's associated FormSelect atom will build a custom rich select component. The component is composed by the FormSelect, FormLabel, FormInput and the FormError atoms.

#### FormGroupSelect / FormSelect - Styles

[](#formgroupselect--formselect---styles)

The FormGroupSelect component and it's associated atoms come with some default styles. You must include them in order to correctly render them.

```
@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-label';
@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-error';
@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-input';
@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-select';
@import './node_modules/lin3s-front-foundation/dist/scss/ui/components/form-group-select';
```

#### FormGroupSelect - Basic setup

[](#formgroupselect---basic-setup)

In order to setup the FormGroupSelect component, we will define every required parameter while including the twig template.

The list of the available parameters, their type and default values are as follows:

ParameterTypeRequiredDefault valuePurposeselect\_idstringyesselect\_namestringnonullselect\_requiredintno0select\_validateintno0select\_validation\_patternstringno''Any valid *RegExp* patternselect\_validation\_typestringno''Built-in *validatory* validation types \['email', 'phone', 'any'\]select\_mobile\_breakpointintno1024select\_max\_height\_mobileintno260select\_max\_height\_desktopintno420select\_is\_filterableintno1select\_filter\_placeholderstringnonullselect\_filter\_order\_bystringno'value'If you set 'label' as this parameter, the component will order it's items by the 'label' while filtering it's options.select\_label\_modifiersstringnonullselect\_label\_contenthtmlnonullselect\_errorsarray
{
 content: string\*,
 modifiers: string
}nonullselect\_select\_modifiersstringnonullselect\_no\_selection\_labelstringno'--'select\_no\_selection\_valuestringno'--'select\_optionsarrayyesThese are the component's options. Each option must have, at least, this shape:
{
 value: string\*
 label: string\*
 selected: int=0
}select\_outside\_click\_to\_close\_enabledintno1This is a full setup example:

```
{% set my_select_options = [{
    label: Male,
    value: 0,
    selected: 1
}, {
    label: Female,
    value: 1
}] %}

{% include '@lin3s_front_foundation/components/form_group_select.html.twig' with {
    select_id: 'my-select',
    select_required: 1,
    select_validate: 1,
    select_validation_pattern: '^(?!.*--).*$',
    select_mobile_breakpoint: 768,
    select_max_height_mobile: 260,
    select_max_height_desktop: 420,
    select_is_filterable: 1,
    select_filter_placeholder: 'Type to filter...',
    select_filter_order_by: 'label',
    select_label_modifiers: null,
    select_label_content: 'My select\'s label',
    select_errors: [{
        content: 'This field is required',
        modifiers: 'form-error--not-filled'
    }, {
        content: 'You cannot select the default value',
        modifiers: 'form-error--not-valid'
    }],
    select_select_modifiers: null,
    select_no_selection_label: '--',
    select_no_selection_value: '--',
    select_options: my_select_options
} %}
```

#### FormSelect - JS API

[](#formselect---js-api)

These are the mostly used methods available on the FormSelect atom's instance.

NameParametersReturned valueDescriptionopen-undefined (void)This method will open the selectclose-undefined (void)This method will close the selectupdate{
 options,
 publishEvent: true
}undefined (void)This method will update the FormSelect's options with the provided ones. By default it will publish the FormSelectOptionSelectedEvent. Each option object must, at least, have the *label* and *value* properties.enable-undefined (void)This method will enable the selectdisable-undefined (void)This method will disable the select#### FormSelect - EventBus events

[](#formselect---eventbus-events)

Each FormSelect instance will publish these events through the EventBus. We will subscribe to these events using some exported helper methods:

```
import {EventBus} from 'lin3s-front-foundation';

const domNode = document.querySelector('.my-form-select');

EventBus.onFormSelectInitialized(domNode, formSelectInitializedEvent => {
  const formSelectInstance = formSelectInitializedEvent.formSelectInstance;
});

EventBus.onFormSelectOptionSelected(domNode, formSelectOptionSelectedEvent => {
  const selectedValue = formSelectOptionSelectedEvent.optionValue;
});

EventBus.onFormSelectStateChanged(domNode, formSelectStateChangedEvent => {
  const formSelectState = formSelectStateChangedEvent.state;
});
```

TypePropertiesFormSelectInitializedEventformSelectInstance: FormSelectFormSelectOptionSelectedEventformSelectInstance: FormSelect
marker: Your marker object representationFormSelectStateChangedEventformSelectInstance: FormSelect
state: \[FormSelect.STATE.OPENED | FormSelect.STATE.CLOSED\]---

### FormGroupTextarea

[](#formgrouptextarea)

The component is composed by the FormTextarea, FormLabel and the FormError atoms.

#### FormGroupTextarea - Styles

[](#formgrouptextarea---styles)

The FormGroupTextarea component and it's associated atoms come with some default styles. You must include them in order to correctly render them.

```
@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-label';
@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-error';
@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-textarea';
@import './node_modules/lin3s-front-foundation/dist/scss/ui/components/form-group-textarea';
```

#### FormGroupTextarea - Setup

[](#formgrouptextarea---setup)

In order to setup the FormGroupTextarea component, we will define every required parameter while including the twig template.

The list of the available parameters, their type and default values are as follows:

ParameterTypeRequiredDefault valuePurposeclass\_namestringnonullmodifiersstringnonulltextarea\_idstringnonulltextarea\_namestringnonulltextarea\_valuestringnonulltextarea\_requiredintno0textarea\_validateintno0textarea\_validation\_patternstringno''Any valid *RegExp* patterntextarea\_validation\_typestringno''Built-in *validatory* validation types \['email', 'phone', 'any'\]textarea\_label\_class\_namestringno''textarea\_label\_modifiersstringno''textarea\_label\_contenthtmlnonulltextarea\_errorsarray
{
 content: string\*,
 modifiers: string
}nonulltextarea\_modifiersstringno''textarea\_placeholderstringno''textarea\_spinnerintno0This is a full setup example:

```
{% include '@lin3s_front_foundation/components/form_group_textarea.html.twig' with {
    textarea_id: 'palindrome',
    textarea_required: 1,
    textarea_validate: 1,
    textarea_validation_pattern: '\\b(\\w)?(\\w)\\w?\\2\\1', {# Note that backslashes must be escaped (\ -> \\) #},
    textarea_label_content: '2-5 letter palindrome',
    textarea_errors: [{
        content: 'This field is required',
        modifiers: 'form-error--not-filled'
    }, {
        content: 'Entered text does not include a valid 2-5 letter palindrome',
        modifiers: 'form-error--not-valid'
    }],
    textarea_spinner: 1
} %}
```

---

### FormGroupCheckbox

[](#formgroupcheckbox)

The component is composed by the FormCheckbox, FormLabel and the FormError atoms.

#### FormGroupCheckbox - Styles

[](#formgroupcheckbox---styles)

The FormGroupCheckbox component and it's associated atoms come with some default styles. You must include them in order to correctly render them.

```
@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-label';
@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-error';
@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-checkbox';
@import './node_modules/lin3s-front-foundation/dist/scss/ui/components/form-group-checkbox';
```

#### FormGroupCheckbox - Setup

[](#formgroupcheckbox---setup)

In order to setup the FormGroupCheckbox component, we will define every required parameter while including the twig template.

The list of the available parameters, their type and default values are as follows:

ParameterTypeRequiredDefault valuePurposeclass\_namestringnonullmodifiersstringnonullcheckbox\_idstringnonullcheckbox\_namestringnonullcheckbox\_requiredintno0checkbox\_validateintno0checkbox\_label\_class\_namestringno''checkbox\_label\_modifiersstringno''checkbox\_label\_contenthtmlnonullcheckbox\_errorsarray
{
 content: string\*,
 modifiers: string
}nonullcheckbox\_modifiersstringno''checkbox\_contentstringyesThis is a full setup example:

```
{% include '@lin3s_front_foundation/components/form_group_checkbox.html.twig' with {
    checkbox_id: 'palindrome',
    checkbox_required: 1,
    checkbox_validate: 1,
    checkbox_content: 'I hace read and accept the terms and conditions',
    textarea_errors: [{
        content: 'Yout must accept the terms and conditions',
        modifiers: 'form-error--not-filled'
    }]
} %}
```

---

---

Usage - Available UI (React) components
---------------------------------------

[](#usage---available-ui-react-components)

### FormGroupSelect (React) component

[](#formgroupselect-react-component)

This React component will build a FormGroupSelect (vanilla) counterpart.

#### FormGroupSelect (React) - Basic setup

[](#formgroupselect-react---basic-setup)

This is a [controlled component](https://facebook.github.io/react/docs/forms.html#controlled-components). For a full initialization example, take a look at the provided example [initialization](https://github.com/LIN3S/FrontFoundation/blob/master/tests/app/src/js/React/init.js) and [FormGroupSelect use case](https://github.com/LIN3S/FrontFoundation/blob/master/tests/app/src/js/React/ReactFormSelect.js).

---

---

Usage - Available UI atoms
--------------------------

[](#usage---available-ui-atoms)

### FormLabel

[](#formlabel)

This atom will render an html `` with some custom attributes.

The list of the available parameters, their type and default values are as follows:

ParameterTypeRequiredDefault valuelabel\_forstringnonulllabel\_requiredintno0label\_class\_namestringnonulllabel\_modifiersstringnonulllabel\_contenthtmlyes-This is a common setup example:

```
{% include '@lin3s_front_foundation/atoms/form_label.html.twig' with {
    label_for: 'user-email',
    label_required: 1,
    label_content: 'Email:'
} %}
```

#### FormLabel - Customization

[](#formlabel---customization)

In order to customize the atom's appearance, you should define these variables before importing the involved scss file.

```
$form-label-text-color: #222 !default;
$form-label-text-color-required: #f00 !default;
$form-label-font-family: sans-serif !default;
$form-label-font-size: 16px !default;
$form-label-font-weight: bold !default;
$form-label-line-height: 20px !default;

@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-label';
```

---

### FormError

[](#formerror)

This atom will render a form-input associated error.

The list of the available parameters, their type and default values are as follows:

ParameterTypeRequiredDefault valueerror\_contentstringyes-error\_class\_namestringnonullThis is a common setup example:

```
{% include '@lin3s_front_foundation/atoms/form_error.html.twig' with {
    error_content: 'This field is required.'
} %}
```

#### FormError - Customization

[](#formerror---customization)

In order to customize the atom's appearance, you should define these variables before importing the involved scss file.

```
$form-error-background-color: #f2b8c2 !default;
$form-error-text-color: #b20008 !default;
$form-error-border-color: rgba($form-error-text-color, .5) !default;
$form-error-animation: $animation-vertical-node-in !default;
$form-error-font-family: sans-serif !default;
$form-error-font-size: 14px !default;
$form-error-font-weight: normal !default;
$form-error-line-height: 18px !default;

@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-error';
```

---

### FormInput

[](#forminput)

This atom will render a form input.

The list of the available parameters, their type and default values are as follows:

ParameterTypeRequiredDefault valueinput\_idstringno-input\_namestringnonullinput\_valuestringnonullinput\_requiredintno0input\_typestringno'text'input\_placeholderstringnonullinput\_class\_namestringnonullinput\_modifiersstringnonullinput\_validateintno0input\_validation\_patternstringnonullinput\_validation\_typestringnonullinput\_focusableintno1This is a common setup example:

```
{% include '@lin3s_front_foundation/atoms/form_input.html.twig' with {
    input_placeholder: 'Enter some data...'
} %}
```

#### FormInput - Customization

[](#forminput---customization)

In order to customize the atom's appearance, you should define these variables before importing the involved scss file.

```
$form-input-border-color: #d1d1d1 !default;
$form-input-border-color-hover: #0e8fff !default;
$form-input-placeholder-text-color: rgba(#444, .8) !default;
$form-input-font-family: sans-serif !default;
$form-input-font-size: 16px !default;
$form-input-font-size-small: 14px !default;
$form-input-font-weight: normal !default;
$form-input-line-height: 20px !default;
$form-input-line-height-small: 18px !default;

@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-input';
```

---

### FormSelect

[](#formselect)

This atom will render a custom rich form select.

The list of the available parameters, their type and default values are as follows:

ParameterTypeRequiredDefault valueselect\_idstringno-select\_namestringnonullselect\_requiredintno0select\_class\_namestringnonullselect\_modifiersstringnonullselect\_no\_selection\_labelstringno'--'select\_no\_selection\_valuestringno'--'select\_mobile\_breakpointintno1024select\_max\_height\_mobileintno260select\_max\_height\_desktopintno420select\_is\_filterableboolno1select\_filter\_placeholderstringnonullselect\_filter\_order\_bystring ('label'|'value')no'value'select\_optionsarrayyesThese are the atom's options. Each option must have, at least, this shape:
{
 value: string\*
 label: string\*
 selected: int=0
}select\_is\_filterableintno1select\_outside\_click\_to\_close\_enabledintno1select\_validateintno0select\_validation\_patternstringnonullselect\_validation\_typestringnonullThis is a common setup example:

```
{% set my_select_options = [{
    label: Male,
    value: 0,
    selected: 1
}, {
    label: Female,
    value: 1
}] %}

{% include '@lin3s_front_foundation/atoms/form_select.html.twig' with {
    select_class_name: 'form-select-demo',
    select_id: 'form-select-1',
    select_required: 1,
    select_filter_placeholder: 'Type to filter...',
    select_outside_click_to_close_enabled: 1,
    select_options: my_select_options
} %}
```

#### FormSelect - Customization

[](#formselect---customization)

In order to customize the atom's appearance, you should define these variables before importing the involved scss file.

```
$form-select-background-color: #fff !default;
$form-select-background-color-disabled: #eee !default;
$form-select-border-color: #d1d1d1 !default;
$form-select-font-family: sans-serif !default;
$form-select-font-size: 16px !default;
$form-select-font-weight: normal !default;
$form-select-line-height: 20px !default;
$form-select-label-text-color: #222 !default;
$form-select-label-text-color-opened: rgba($form-select-label-text-color, .5) !default;
$form-select-options-box-shadow: 0 5px 30px -10px rgba(#222, .25) !default;
$form-select-option-text-color: #222 !default;
$form-select-option-text-color-active: #fff !default;
$form-select-option-background-color-active: #0e8fff !default;
$form-select-option-background-color-hover: #eee !default;
$form-select-option-background-color-hover-and-active: rgba($form-select-option-background-color-active, .8) !default;

@import './node_modules/lin3s-front-foundation/dist/scss/ui/atoms/form-select';
```

---

### Picture

[](#picture)

This atom will render a picture element with different sources depending on browser size and orientation.

The list of the available parameters, their type and default values are as follows:

ParameterTypeRequiredDefault valuepicture\_class\_namestringnonullpicture\_image\_class\_namestringnonullpicture\_altstringnonullpicture\_src\_smallstringyes-picture\_src\_mediumstringyes-picture\_src\_largestringyes-picture\_src\_xlargestringyes-picture\_src\_xxlargestringyes-picture\_small\_breakpointintno640picture\_medium\_breakpointintno1024picture\_large\_breakpointintno1200picture\_xlarge\_breakpointintno1440picture\_custom\_srcsethtmlnonullThis is a common setup example:

```
{% embed '@lin3s_front_foundation/atoms/picture.html.twig' with {
    picture_class_name: 'my-picture',
    picture_image_class_name: 'my-picture__image',
    picture_alt: 'Some alt text',
    picture_src_small: 'http://mydomain.com/small-image.jpg',
    picture_src_medium: 'http://mydomain.com/medium-image.jpg',
    picture_src_large: 'http://mydomain.com/large-image.jpg',
    picture_src_xlarge: 'http://mydomain.com/xlarge-image.jpg',
    picture_src_xxlarge: 'http://mydomain.com/xxlarge-image.jpg',
    picture_small_breakpoint: 768,
} %}
    {% block custom_srcset %}

    {% endblock %}
{% endembed %}
```

---

---

Usage - Available macros
------------------------

[](#usage---available-macros)

The library provides you opinionated macros for rendering the form components with pre-defined parameters.

### Atoms - form\_inputs

[](#atoms---form_inputs)

```
{% macro required(type, id, placeholder, name) %}
{% macro email(id, placeholder, name) %}
{% macro requiredEmail(id, placeholder, name) %}
{% macro phone(id, placeholder, name) %}
{% macro requiredPhone(id, placeholder, name) %}
```

---

### Components - form\_group\_checkboxes

[](#components---form_group_checkboxes)

```
{% macro required(id, label, content, errors) %}
```

---

### Components - form\_group\_inputs

[](#components---form_group_inputs)

```
{% macro required(type, id, placeholder, label, errors, name) %}
{% macro email(id, placeholder, label, errors, name) %}
{% macro requiredEmail(id, placeholder, label, errors, name) %}
{% macro phone(id, placeholder, label, errors, name) %}
{% macro requiredPhone(id, placeholder, label, errors, name) %}
```

---

### Components - form\_group\_selects

[](#components---form_group_selects)

```
{% macro required(id, filter_placeholder, label, options, errors) %}
{% macro requiredAndNot(id, filter_placeholder, label, not_valid_value, options, errors) %}
```

---

### Components - form\_group\_textareas

[](#components---form_group_textareas)

```
{% macro required(id, placeholder, label, errors) %}
{% macro requiredWithPattern(id, placeholder, label, pattern, errors) %}
```

---

---

Validatory
----------

[](#validatory)

FrontFoundation provides `js` and `scss` utility/helper code to work with the [validatory](https://github.com/FriendsOfECMAScript/Validatory) librar to make easier our initialization or style customization.

### Validatory - initWithEvents &amp; EventBus subscriptions

[](#validatory---initwithevents--eventbus-subscriptions)

FrontFoundation library provides an utility method `EventBus.validatory.initWithEvents` for initializing the [validatory](https://github.com/FriendsOfECMAScript/Validatory) library coupled to the [lin3s-event-bus](https://github.com/FriendsOfECMAScript/Validatory) library, so our app can be notified when a form, or any of it's element's validation state changes using the exposed `EventBus.validatory.onFormStateChanged` and `EventBus.validatory.onFormElementStateChanged` subscriptions.

```
import {EventBus} from 'lin3s-front-foundation';

EventBus.validatory.initWithEvents({
  formSelector: '#validatory-form',
  formElementSelector: '#validatory-form input, #validatory-form select, #validatory-form textarea'
});

// Event subscriptions through the event-bus

const myForm = document.getElementById('validatory-form');

EventBus.validatory.onFormStateChanged(myForm, stateChangedEvent => {
  // Do what you want with the provided payload object
  console.log(stateChangedEvent.formValidatorInstance);
});

const myFormElement = document.querySelector('#validatory-form .zip-code');

EventBus.validatory.onFormElementStateChanged(myFormElement, stateChangedEvent => {
  // Do what you want with the provided payload object
  console.log(stateChangedEvent.formElementValidatorInstance);
});
```

### Validatory - custom validators and UI customization

[](#validatory---custom-validators-and-ui-customization)

In order to build and append a custom validator, we must first prepare the twig markup, then write our custom validator, and add some needed scss.

Note that we are adding some custom validation error messages/markup. (`form-error--not-valid-zip-code`, `form-error--not-valid-no-service`). These custom errors will match the custom validator's resolved `errorCode`s.

```
{% include '@lin3s_front_foundation/components/form_group_input.html.twig' with {
    input_id: 'zip-code',
    input_required: 1,
    input_validate: 1,
    input_validation_type: 'phone',
    input_placeholder: 'Enter your zip code',
    input_label_content: 'Zip code',
    input_errors: [{
        content: 'This field is required',
        modifiers: 'form-error--not-filled'
    }, {
        content: 'The entered value does not seem ot be a valid zip code',
        modifiers: 'form-error--not-valid-zip-code'
    }, , {
        content: 'Sorry, we are not providing service in the entered zip code's area.',
        modifiers: 'form-error--not-valid-no-service'
    }],
    input_spinner: 1
} %}
```

```
import debounce from 'es6-promise-debounce';
import {validatorRegistry, Validator, asyncValidation} from 'validatory';

const
  debouncedValidation = debounce(node => {
    console.log('Asynchronous validation started');

    const validZipCode = /^\d{5}$/.test(node.value); // zip code format validation

    if (!validZipCode) {
      return {valid: false, errorCode: 'zip-code'}; // will match the DOM markup's .form-error--not-valid-zip-code
    }

    return asyncValidation(fetch('https://jsonplaceholder.typicode.com/posts/1'), response => {
      const valid = node.value === '01005';

      return valid ? {valid} : {valid: false, errorCode: 'no-service'}; // will match the DOM markup's .form-error--not-valid-no-service
    });
  }, 500),
  asyncValidator = new Validator({
    supports: node => node.id === 'async',
    isEmpty: node => node.value === '',
    isValid: node => debouncedValidation(node),
  });

validatorRegistry.add(asyncValidator);
```

```
@import './../../node_modules/lin3s-front-foundation/dist/scss/_mixins/form-validation';

@include form_group_custom_error('.form-group-input__errors', 'zip-code');
@include form_group_custom_error('.form-group-input__errors', 'no-service');
```

---

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity18

Limited adoption so far

Community16

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 79.4% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~9 days

Recently: every ~16 days

Total

33

Last Release

2858d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/b54f0877b7c31df24820fc1c55bd1a4dcda487dbe8ae5b031e6bf8362fecdfe4?d=identicon)[gorkalaucirica](/maintainers/gorkalaucirica)

![](https://www.gravatar.com/avatar/06308bfc15d8774c16d36d727f852c2d29ed8d0d6153637384439747776dc658?d=identicon)[benatespina](/maintainers/benatespina)

---

Top Contributors

[![mktoast](https://avatars.githubusercontent.com/u/4963232?v=4)](https://github.com/mktoast "mktoast (139 commits)")[![benatespina](https://avatars.githubusercontent.com/u/3951376?v=4)](https://github.com/benatespina "benatespina (26 commits)")[![AnderRV](https://avatars.githubusercontent.com/u/1824554?v=4)](https://github.com/AnderRV "AnderRV (7 commits)")[![andresmontejo](https://avatars.githubusercontent.com/u/32167234?v=4)](https://github.com/andresmontejo "andresmontejo (3 commits)")

---

Tags

cssfoundationfrontendjavascriptscsstwig

### Embed Badge

![Health badge](/badges/lin3s-front-foundation/health.svg)

```
[![Health](https://phpackages.com/badges/lin3s-front-foundation/health.svg)](https://phpackages.com/packages/lin3s-front-foundation)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
