Picker

Picker is a powerful component that allows you to create custom overlay pickers which looks like iOS native picker.

Picker could be used as inline component or as overlay. Overlay Picker will be automatically converted to Popover on tablets (iPad).

Picker App Methods

Let's look at related App methods to work with Picker:

app.picker.create(parameters)- create Picker instance

  • parameters - object. Object with picker parameters

Method returns created Picker's instance

app.picker.destroy(el)- destroy Picker instance

  • el - HTMLElement or string (with CSS Selector) or object. Picker element or Picker instance to destroy.

app.picker.get(el)- get Picker instance by HTML element

  • el - HTMLElement or string (with CSS Selector). Picker element.

Method returns Picker's instance

app.picker.close(el)- close Picker

  • el - HTMLElement or string (with CSS Selector). Picker element to close.

Method returns Picker's instance

For example:

var picker = app.picker.create({
  inputEl: '#picker-input',
  cols: [
     {
       values: ['apple', 'orange', 'banana'],
       displayValues: ['Apple', 'Orange', 'Banana'],
     }
   ]
});

Picker Parameters

Let's look on list of all available Picker parameters:

ParameterTypeDefaultDescription
rotateEffectbooleanfalseEnables 3D rotate effect
freeModebooleanfalseDisables snapping on values
valuearrayArray with initial values. Each array item represents value of related column
formatValuefunction (values, displayValues)Function to format input value, should return new/formatted string value. values and displayValues are arrays where each item represents value/display value of related column
colsarrayArray with columns. Each array item represents object with column parameters
Container/opener-specific parameters
containerElstring
HTMLElement
String with CSS selector or HTMLElement where to place generated Picker HTML. Use only for inline picker
openInstringautoCan be auto, popover (to open picker in popover), sheet (to open in sheet modal). In case of auto will open in sheet modal on small screens and in popover on large screens.
backdropbooleanEnables backdrop for Picker container (Popover or Sheet) (dark semi transparent layer behind). By default it uses default value based on how it is opened (in Sheet or Popover).
sheetPushbooleanfalseEnables Picker sheet to push view/s behind on open
sheetSwipeToClosebooleanfalseEnables ability to close Picker sheet with swipe
inputElstring or HTMLElementString with CSS selector or HTMLElement with related input element
scrollToInputbooleantrueScroll viewport (page-content) to input when picker opened
inputReadOnlybooleantrueSets "readonly" attribute on specified input
cssClassstringAdditional CSS class name to be set on picker element
closeByOutsideClickbooleantrueIf enabled, picker will be closed by clicking outside of picker or related input element
toolbarbooleantrueEnables picker toolbar
toolbarCloseTextstringDoneText for Done/Close toolbar button
routableModalsbooleanfalseWill add opened picker to router history which gives ability to close picker by going back in router history and set current route to the picker modal
urlstringselect/Picker modal URL that will be set as a current route
viewobjectView where to set routing when routableModals enabled. Defaults to parent view of inputEl or main view if not found parent view
Render Functions
renderToolbarfunctionFunction to render toolbar. Must return toolbar HTML string
renderfunctionFunction to render whole picker. Must return picker full HTML string
Events
onobject

Object with events handlers. For example:

var picker = app.picker.create({
  ...
  on: {
    opened: function () {
      console.log('Picker opened')
    }
  }
})

Note that all following parameters can be used in global app parameters under picker property to set defaults for all pickers. For example:

var app = new Framework7({
  picker: {
    rotateEffect: true,
    openIn: 'popover',
  }
});

Column Parameters

When we configure Picker we need to pass cols parameter. It is an array where each item is an object with column parameters:

ParameterTypeDefaultDescription
valuesarrayArray with string columns values
displayValuesarrayArray with string columns values that will be displayed in Picker. If not specified, it will display values from values parameter
cssClassstringAdditional CSS class name to be set on column HTML container
textAlignstringText alignment of column values, could be "left", "center" or "right"
widthnumberColumn width in px. Useful if you need to fix column widths in picker with dependent columns. By default, calculated automatically
dividerbooleanfalseDefines column that should be used as a visual divider, that doesn't have any values
contentstringShould be specified for divider-column (divider:true) with content of the column
onChangefunction(picker, value, displayValue)Callback function that will be executed when picker value changed.

Picker Methods & Properties

After we initialize Picker we have its initialized instance in variable (like picker variable in examples above) with helpful methods and properties:

Properties
picker.appLink to global app instance
picker.containerElPicker wrapping container HTML element (when inline picker is in use)
picker.$containerElDom7 instance with picker wrapping container HTML element (when inline picker is in use)
picker.elPicker HTML element
picker.$elDom7 instance with picker HTML element
picker.inputElPicker input HTML element (passed in inputEl parameter)
picker.$inputElDom7 instance with picker input HTML element (passed in inputEl parameter)
picker.valueArray where each item represents current selected value for each column
picker.colsArray with specified Picker columns. Each column also has its own methods and properties (look below)
picker.openedtrue if Picker is currently opened
picker.inlinetrue when inline picker is in use
picker.urlPicker URL (that was passed in url parameter)
picker.viewPicker View (that was passed in view parameter) or found parent view
picker.paramsObject with initialization parameters
Methods
picker.setValue(values)Set new picker value. values is array where each item represents value for each column.
picker.getValue()Returns current picker value
picker.open()Open Picker
picker.close()Close Picker
picker.destroy()Destroy Picker instance and remove all events
picker.on(event, handler)Add event handler
picker.once(event, handler)Add event handler that will be removed after it was fired
picker.off(event, handler)Remove event handler
picker.off(event)Remove all handlers for specified event
picker.emit(event, ...args)Fire event on instance

Column Methods & Properties

Each column in picker.cols array also has its own useful methods and properties.

//Get first column
var col = picker.cols[0];
Properties
col.elColumn HTML element
col.$elDom7 instance with column HTML container
col.itemsDom7 instance with column items HTML elements
col.valueCurrently selected column value
col.displayValueCurrently selected column display value
col.activeIndexIndex number of currently selected/active item
Methods
col.setValue(value)Set new value for current column. value is a new value.
col.replaceValues(values, displayValues)Replace column values and displayValues with new ones

Picker Events

Picker will fire the following DOM events on picker element and events on app and picker instance:

DOM Events

EventTargetDescription
picker:openPicker Element<div class="picker">Event will be triggered when Picker starts its opening animation
picker:openedPicker Element<div class="picker">Event will be triggered after Picker completes its opening animation
picker:closePicker Element<div class="picker">Event will be triggered when Picker starts its closing animation
picker:closedPicker Element<div class="picker">Event will be triggered after Picker completes its closing animation

App and Picker Instance Events

Picker instance emits events on both self instance and app instance. App instance events has same names prefixed with picker.

EventTargetArgumentsDescription
changepicker(picker, value, displayValue)Event will be triggered when picker value changes
pickerChangeapp
initpicker(picker)Event will be triggered when picker initialized
pickerInitapp
openpicker(picker)Event will be triggered when Picker starts its opening animation. As an argument event handler receives picker instance
pickerOpenapp
openedpicker(picker)Event will be triggered after Picker completes its opening animation. As an argument event handler receives picker instance
pickerOpenedapp
closepicker(picker)Event will be triggered when Picker starts its closing animation. As an argument event handler receives picker instance
pickerCloseapp
closedpicker(picker)Event will be triggered after Picker completes its closing animation. As an argument event handler receives picker instance
pickerClosedapp
beforeDestroypicker(picker)Event will be triggered right before Picker instance will be destroyed. As an argument event handler receives picker instance
pickerBeforeDestroyapp

CSS Variables

Below is the list of related CSS variables (CSS custom properties).

Note that commented variables are not specified by default and their values is what they fallback to in this case.

:root {
  --f7-picker-height: 260px;
  --f7-picker-inline-height: 200px;
  --f7-picker-popover-height: 260px;
  --f7-picker-popover-width: 280px;
  --f7-picker-landscape-height: 200px;
  --f7-picker-item-height: 36px;
  /*
  --f7-picker-sheet-bg-color: var(--f7-sheet-bg-color);
  */
}
.ios {
  --f7-picker-column-font-size: 20px;
  --f7-picker-item-selected-text-color: #000;
  --f7-picker-item-selected-bg-color: rgba(0, 0, 0, 0.12);
  --f7-picker-divider-text-color: #000;
  --f7-picker-item-text-color: rgba(0, 0, 0, 0.45);
}
.ios .dark,
.ios.dark {
  --f7-picker-item-selected-text-color: #fff;
  --f7-picker-item-selected-bg-color: rgba(255, 255, 255, 0.1);
  --f7-picker-divider-text-color: #fff;
  --f7-picker-item-text-color: rgba(255, 255, 255, 0.55);
}
.md {
  --f7-picker-column-font-size: 20px;
}
.md,
.md .dark,
.md [class*='color-'] {
  --f7-picker-item-selected-text-color: var(--f7-md-on-surface);
  --f7-picker-item-text-color: var(--f7-md-on-surface-variant);
  --f7-picker-divider-text-color: var(--f7-md-on-surface);
  --f7-picker-item-selected-border-color: var(--f7-md-outline);
}

Examples

picker.html
<template>
  <div class="page">
    <div class="navbar">
      <div class="navbar-bg"></div>
      <div class="navbar-inner sliding">
        <div class="title">Picker</div>
      </div>
    </div>
    <div class="page-content">
      <div class="block">
        <p>Picker is a powerful component that allows you to create custom overlay pickers which looks like native
          picker.</p>
        <p>Picker could be used as inline component or as overlay. Overlay Picker will be automatically converted to
          Popover on tablets (iPad).</p>
      </div>
      <div class="block-title">Picker with single value</div>
      <div class="list list-strong-ios list-outline-ios">
        <ul>
          <li>
            <div class="item-content item-input">
              <div class="item-inner">
                <div class="item-input-wrap">
                  <input type="text" placeholder="Your iOS device" readonly="readonly" id="demo-picker-device" />
                </div>
              </div>
            </div>
          </li>
        </ul>
      </div>
      <div class="block-title">2 values and 3d-rotate effect</div>
      <div class="list list-strong-ios list-outline-ios">
        <ul>
          <li>
            <div class="item-content item-input">
              <div class="item-inner">
                <div class="item-input-wrap">
                  <input type="text" placeholder="Describe yourself" readonly="readonly" id="demo-picker-describe" />
                </div>
              </div>
            </div>
          </li>
        </ul>
      </div>
      <div class="block-title">Dependent values</div>
      <div class="list list-strong-ios list-outline-ios">
        <ul>
          <li>
            <div class="item-content item-input">
              <div class="item-inner">
                <div class="item-input-wrap">
                  <input type="text" placeholder="Your car" readonly="readonly" id="demo-picker-dependent" />
                </div>
              </div>
            </div>
          </li>
        </ul>
      </div>
      <div class="block-title">Custom toolbar</div>
      <div class="list list-strong-ios list-outline-ios">
        <ul>
          <li>
            <div class="item-content item-input">
              <div class="item-inner">
                <div class="item-input-wrap">
                  <input type="text" placeholder="Describe yourself" readonly="readonly"
                    id="demo-picker-custom-toolbar" />
                </div>
              </div>
            </div>
          </li>
        </ul>
      </div>
      <div class="block-title">Inline Picker / Date-time</div>
      <div class="list no-margin">
        <ul>
          <li>
            <div class="item-content item-input">
              <div class="item-inner">
                <div class="item-input-wrap">
                  <input type="text" placeholder="Date Time" readonly="readonly" id="demo-picker-date" />
                </div>
              </div>
            </div>
          </li>
        </ul>
      </div>
      <div class="block block-strong block-outline-ios inset-md no-padding no-margin-top">
        <div id="demo-picker-date-container"></div>
      </div>
    </div>
  </div>
</template>
<script>
  export default (props, { $f7, $on }) => {
    let pickerDevice;
    let pickerDescribe;
    let pickerDependent;
    let pickerCustomToolbar;

    $on('pageInit', () => {
      // iOS Device picker
      pickerDevice = $f7.picker.create({
        inputEl: '#demo-picker-device',
        cols: [
          {
            textAlign: 'center',
            values: ['iPhone 4', 'iPhone 4S', 'iPhone 5', 'iPhone 5S', 'iPhone 6', 'iPhone 6 Plus', 'iPad 2', 'iPad Retina', 'iPad Air', 'iPad mini', 'iPad mini 2', 'iPad mini 3']
          }
        ]
      });

      // Describe yourself picker
      pickerDescribe = $f7.picker.create({
        inputEl: '#demo-picker-describe',
        rotateEffect: true,
        cols: [
          {
            textAlign: 'left',
            values: ('Super Amazing Bat Iron Rocket Lex Beautiful Wonderful Raining Happy Funny Cool Hot').split(' ')
          },
          {
            values: ('Man Luthor Woman Boy Girl Person Cutie Babe Raccoon').split(' ')
          },
        ]
      });

      // Dependent values
      var carVendors = {
        Japanese: ['Honda', 'Lexus', 'Mazda', 'Nissan', 'Toyota'],
        German: ['Audi', 'BMW', 'Mercedes', 'Volkswagen', 'Volvo'],
        American: ['Cadillac', 'Chrysler', 'Dodge', 'Ford']
      };
      pickerDependent = $f7.picker.create({
        inputEl: '#demo-picker-dependent',
        rotateEffect: true,
        formatValue: function (values) {
          return values[1];
        },
        cols: [
          {
            textAlign: 'left',
            values: ['Japanese', 'German', 'American'],
            onChange: function (picker, country) {
              if (picker.cols[1].replaceValues) {
                picker.cols[1].replaceValues(carVendors[country]);
              }
            }
          },
          {
            values: carVendors.Japanese,
            width: 160,
          },
        ]
      });

      // Custom Toolbar
      pickerCustomToolbar = $f7.picker.create({
        inputEl: '#demo-picker-custom-toolbar',
        rotateEffect: true,
        renderToolbar: function () {
          return '<div class="toolbar">' +
            '<div class="toolbar-inner">' +
            '<div class="left">' +
            '<a  class="link toolbar-randomize-link">Randomize</a>' +
            '</div>' +
            '<div class="right">' +
            '<a  class="link sheet-close popover-close">That\'s me</a>' +
            '</div>' +
            '</div>' +
            '</div>';
        },
        cols: [
          {
            values: ['Mr', 'Ms'],
          },
          {
            textAlign: 'left',
            values: ('Super Amazing Bat Iron Rocket Lex Beautiful Wonderful Raining Happy Funny Cool Hot').split(' ')
          },
          {
            values: ('Man Luthor Woman Boy Girl Person Cutie Babe Raccoon').split(' ')
          },
        ],
        on: {
          open: function (picker) {
            picker.$el.find('.toolbar-randomize-link').on('click', function () {
              var col0Values = picker.cols[0].values;
              var col0Random = col0Values[Math.floor(Math.random() * col0Values.length)];

              var col1Values = picker.cols[1].values;
              var col1Random = col1Values[Math.floor(Math.random() * col1Values.length)];

              var col2Values = picker.cols[2].values;
              var col2Random = col2Values[Math.floor(Math.random() * col2Values.length)];

              picker.setValue([col0Random, col1Random, col2Random]);
            });
          },
        }
      });
      // Inline date-time
      const today = new Date();
      pickerInline = $f7.picker.create({
        containerEl: '#demo-picker-date-container',
        inputEl: '#demo-picker-date',
        toolbar: false,
        rotateEffect: true,
        value: [
          today.getMonth(),
          today.getDate(),
          today.getFullYear(),
          today.getHours(),
          today.getMinutes() < 10 ? '0' + today.getMinutes() : today.getMinutes()
        ],
        formatValue: function (values, displayValues) {
          return displayValues[0] + ' ' + values[1] + ', ' + values[2] + ' ' + values[3] + ':' + values[4];
        },
        cols: [
          // Months
          {
            values: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
            displayValues: ('January February March April May June July August September October November December').split(' '),
            textAlign: 'left'
          },
          // Days
          {
            values: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31],
          },
          // Years
          {
            values: (function () {
              var arr = [];
              for (var i = 1950; i <= 2030; i++) { arr.push(i); }
              return arr;
            })(),
          },
          // Space divider
          {
            divider: true,
            content: '&nbsp;&nbsp;'
          },
          // Hours
          {
            values: (function () {
              var arr = [];
              for (var i = 0; i <= 23; i++) { arr.push(i); }
              return arr;
            })(),
          },
          // Divider
          {
            divider: true,
            content: ':'
          },
          // Minutes
          {
            values: (function () {
              var arr = [];
              for (var i = 0; i <= 59; i++) { arr.push(i < 10 ? '0' + i : i); }
              return arr;
            })(),
          }
        ],
        on: {
          change: function (picker, values, displayValues) {
            var daysInMonth = new Date(picker.value[2], picker.value[0] * 1 + 1, 0).getDate();
            if (values[1] > daysInMonth) {
              picker.cols[1].setValue(daysInMonth);
            }
          },
        }
      });
    });
    $on('pageBeforeRemove', () => {
      pickerDevice.destroy();
      pickerDescribe.destroy();
      pickerDependent.destroy();
      pickerCustomToolbar.destroy();
    });

    return $render;
  };

</script>