diff --git a/guide/README.md b/guide/README.md
index 9dea08f9..cfa10914 100644
--- a/guide/README.md
+++ b/guide/README.md
@@ -157,6 +157,17 @@ You can access to select2 as follows
 this.refs.tags.el
 ```
 
+### Full version
+
+Some options are only available with [`Select2.full.js`](https://select2.org/getting-started/builds-and-modules).
+To use that version instead:
+
+```js
+import Select2 from 'react-select2-wrapper/lib/components/Select2.full';
+````
+
+Everything else will be the same as before.
+
 ## Themes
 
 Default theme in [css/select2.css](../css/select2.css)
diff --git a/src/components/Select2.full.js b/src/components/Select2.full.js
new file mode 100644
index 00000000..37d28915
--- /dev/null
+++ b/src/components/Select2.full.js
@@ -0,0 +1,3 @@
+import 'select2/dist/js/select2.full';
+
+export default from './shared';
diff --git a/src/components/Select2.js b/src/components/Select2.js
index fb413839..635e1255 100644
--- a/src/components/Select2.js
+++ b/src/components/Select2.js
@@ -1,217 +1,3 @@
-import React, { Component } from 'react';
-import PropTypes from 'prop-types';
-import ReactDOM from 'react-dom';
-import shallowEqualFuzzy from 'shallow-equal-fuzzy';
-import $ from 'jquery';
 import 'select2';
 
-const namespace = 'react-select2-wrapper';
-
-export default class Select2 extends Component {
-  static propTypes = {
-    defaultValue: PropTypes.oneOfType([
-      PropTypes.number,
-      PropTypes.array,
-      PropTypes.string,
-    ]),
-    value: PropTypes.oneOfType([
-      PropTypes.number,
-      PropTypes.array,
-      PropTypes.string,
-    ]),
-    data: PropTypes.array,
-    events: PropTypes.array,
-    options: PropTypes.object,
-    multiple: PropTypes.bool,
-    onOpen: PropTypes.func,
-    onClose: PropTypes.func,
-    onSelect: PropTypes.func,
-    onChange: PropTypes.func,
-    onUnselect: PropTypes.func,
-  };
-
-  static defaultProps = {
-    data: [],
-    events: [
-      [`change.${namespace}`, 'onChange'],
-      [`select2:open.${namespace}`, 'onOpen'],
-      [`select2:close.${namespace}`, 'onClose'],
-      [`select2:select.${namespace}`, 'onSelect'],
-      [`select2:unselect.${namespace}`, 'onUnselect'],
-    ],
-    options: {},
-    multiple: false,
-  };
-
-  constructor(props) {
-    super(props);
-    this.el = null;
-    this.forceUpdateValue = false;
-    this.initialRender = true;
-  }
-
-  componentDidMount() {
-    this.initSelect2(this.props);
-    this.updateValue();
-  }
-
-  componentWillReceiveProps(nextProps) {
-    this.initialRender = false;
-    this.updSelect2(nextProps);
-  }
-
-  componentDidUpdate() {
-    this.updateValue();
-  }
-
-  componentWillUnmount() {
-    this.destroySelect2();
-  }
-
-  initSelect2(props) {
-    const { options } = props;
-
-    this.el = $(ReactDOM.findDOMNode(this));
-    // fix for updating selected value when data is changing
-    if (this.forceUpdateValue) {
-      this.updateSelect2Value(null);
-    }
-    this.el.select2(this.prepareOptions(options));
-    this.attachEventHandlers(props);
-  }
-
-  updSelect2(props) {
-    const prevProps = this.props;
-
-    if (!shallowEqualFuzzy(prevProps.data, props.data)) {
-      this.forceUpdateValue = true;
-      this.destroySelect2(false);
-      this.initSelect2(props);
-      return;
-    }
-
-    const { options } = props;
-    if (!shallowEqualFuzzy(prevProps.options, options)) {
-      this.el.select2(this.prepareOptions(options));
-    }
-
-    const handlerChanged = e => prevProps[e[1]] !== props[e[1]];
-    if (props.events.some(handlerChanged)) {
-      this.detachEventHandlers();
-      this.attachEventHandlers(props);
-    }
-  }
-
-  updateSelect2Value(value) {
-    this.el.off(`change.${namespace}`).val(value).trigger('change');
-
-    const onChange = this.props.onChange;
-    if (onChange) {
-      this.el.on(`change.${namespace}`, onChange);
-    }
-  }
-
-  updateValue() {
-    const { value, defaultValue, multiple } = this.props;
-    const newValue = this.prepareValue(value, defaultValue);
-    const currentValue = multiple ? this.el.val() || [] : this.el.val();
-
-    if (!this.fuzzyValuesEqual(currentValue, newValue) || this.forceUpdateValue) {
-      this.updateSelect2Value(newValue);
-      if (!this.initialRender) {
-        this.el.trigger('change');
-      }
-      this.forceUpdateValue = false;
-    }
-  }
-
-  fuzzyValuesEqual(currentValue, newValue) {
-    return (currentValue === null && newValue === '') ||
-      shallowEqualFuzzy(currentValue, newValue);
-  }
-
-  destroySelect2(withCallbacks = true) {
-    if (withCallbacks) {
-      this.detachEventHandlers();
-    }
-
-    this.el.select2('destroy');
-    this.el = null;
-  }
-
-  attachEventHandlers(props) {
-    props.events.forEach(event => {
-      if (typeof props[event[1]] !== 'undefined') {
-        this.el.on(event[0], props[event[1]]);
-      }
-    });
-  }
-
-  detachEventHandlers() {
-    this.props.events.forEach(event => {
-      if (typeof this.props[event[1]] !== 'undefined') {
-        this.el.off(event[0]);
-      }
-    });
-  }
-
-  prepareValue(value, defaultValue) {
-    const issetValue = typeof value !== 'undefined' && value !== null;
-    const issetDefaultValue = typeof defaultValue !== 'undefined';
-
-    if (!issetValue && issetDefaultValue) {
-      return defaultValue;
-    }
-    return value;
-  }
-
-  prepareOptions(options) {
-    const opt = options;
-    if (typeof opt.dropdownParent === 'string') {
-      opt.dropdownParent = $(opt.dropdownParent);
-    }
-    return opt;
-  }
-
-  isObject(value) {
-    const type = typeof value;
-    return type === 'function' || (value && type === 'object') || false;
-  }
-
-  makeOption(item) {
-    if (this.isObject(item)) {
-      const { id, text, ...itemParams } = item;
-      return ();
-    }
-
-    return ();
-  }
-
-  render() {
-    const { data, value, ...props } = this.props;
-
-    delete props.options;
-    delete props.events;
-    delete props.onOpen;
-    delete props.onClose;
-    delete props.onSelect;
-    delete props.onChange;
-    delete props.onUnselect;
-
-    return (
-      
-    );
-  }
-}
+export default from './shared';
diff --git a/src/components/shared.js b/src/components/shared.js
new file mode 100644
index 00000000..2d10b889
--- /dev/null
+++ b/src/components/shared.js
@@ -0,0 +1,216 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import ReactDOM from 'react-dom';
+import shallowEqualFuzzy from 'shallow-equal-fuzzy';
+import $ from 'jquery';
+
+const namespace = 'react-select2-wrapper';
+
+export default class Select2 extends Component {
+  static propTypes = {
+    defaultValue: PropTypes.oneOfType([
+      PropTypes.number,
+      PropTypes.array,
+      PropTypes.string,
+    ]),
+    value: PropTypes.oneOfType([
+      PropTypes.number,
+      PropTypes.array,
+      PropTypes.string,
+    ]),
+    data: PropTypes.array,
+    events: PropTypes.array,
+    options: PropTypes.object,
+    multiple: PropTypes.bool,
+    onOpen: PropTypes.func,
+    onClose: PropTypes.func,
+    onSelect: PropTypes.func,
+    onChange: PropTypes.func,
+    onUnselect: PropTypes.func,
+  };
+
+  static defaultProps = {
+    data: [],
+    events: [
+      [`change.${namespace}`, 'onChange'],
+      [`select2:open.${namespace}`, 'onOpen'],
+      [`select2:close.${namespace}`, 'onClose'],
+      [`select2:select.${namespace}`, 'onSelect'],
+      [`select2:unselect.${namespace}`, 'onUnselect'],
+    ],
+    options: {},
+    multiple: false,
+  };
+
+  constructor(props) {
+    super(props);
+    this.el = null;
+    this.forceUpdateValue = false;
+    this.initialRender = true;
+  }
+
+  componentDidMount() {
+    this.initSelect2(this.props);
+    this.updateValue();
+  }
+
+  componentWillReceiveProps(nextProps) {
+    this.initialRender = false;
+    this.updSelect2(nextProps);
+  }
+
+  componentDidUpdate() {
+    this.updateValue();
+  }
+
+  componentWillUnmount() {
+    this.destroySelect2();
+  }
+
+  initSelect2(props) {
+    const { options } = props;
+
+    this.el = $(ReactDOM.findDOMNode(this));
+    // fix for updating selected value when data is changing
+    if (this.forceUpdateValue) {
+      this.updateSelect2Value(null);
+    }
+    this.el.select2(this.prepareOptions(options));
+    this.attachEventHandlers(props);
+  }
+
+  updSelect2(props) {
+    const prevProps = this.props;
+
+    if (!shallowEqualFuzzy(prevProps.data, props.data)) {
+      this.forceUpdateValue = true;
+      this.destroySelect2(false);
+      this.initSelect2(props);
+      return;
+    }
+
+    const { options } = props;
+    if (!shallowEqualFuzzy(prevProps.options, options)) {
+      this.el.select2(this.prepareOptions(options));
+    }
+
+    const handlerChanged = e => prevProps[e[1]] !== props[e[1]];
+    if (props.events.some(handlerChanged)) {
+      this.detachEventHandlers();
+      this.attachEventHandlers(props);
+    }
+  }
+
+  updateSelect2Value(value) {
+    this.el.off(`change.${namespace}`).val(value).trigger('change');
+
+    const onChange = this.props.onChange;
+    if (onChange) {
+      this.el.on(`change.${namespace}`, onChange);
+    }
+  }
+
+  updateValue() {
+    const { value, defaultValue, multiple } = this.props;
+    const newValue = this.prepareValue(value, defaultValue);
+    const currentValue = multiple ? this.el.val() || [] : this.el.val();
+
+    if (!this.fuzzyValuesEqual(currentValue, newValue) || this.forceUpdateValue) {
+      this.updateSelect2Value(newValue);
+      if (!this.initialRender) {
+        this.el.trigger('change');
+      }
+      this.forceUpdateValue = false;
+    }
+  }
+
+  fuzzyValuesEqual(currentValue, newValue) {
+    return (currentValue === null && newValue === '') ||
+      shallowEqualFuzzy(currentValue, newValue);
+  }
+
+  destroySelect2(withCallbacks = true) {
+    if (withCallbacks) {
+      this.detachEventHandlers();
+    }
+
+    this.el.select2('destroy');
+    this.el = null;
+  }
+
+  attachEventHandlers(props) {
+    props.events.forEach(event => {
+      if (typeof props[event[1]] !== 'undefined') {
+        this.el.on(event[0], props[event[1]]);
+      }
+    });
+  }
+
+  detachEventHandlers() {
+    this.props.events.forEach(event => {
+      if (typeof this.props[event[1]] !== 'undefined') {
+        this.el.off(event[0]);
+      }
+    });
+  }
+
+  prepareValue(value, defaultValue) {
+    const issetValue = typeof value !== 'undefined' && value !== null;
+    const issetDefaultValue = typeof defaultValue !== 'undefined';
+
+    if (!issetValue && issetDefaultValue) {
+      return defaultValue;
+    }
+    return value;
+  }
+
+  prepareOptions(options) {
+    const opt = options;
+    if (typeof opt.dropdownParent === 'string') {
+      opt.dropdownParent = $(opt.dropdownParent);
+    }
+    return opt;
+  }
+
+  isObject(value) {
+    const type = typeof value;
+    return type === 'function' || (value && type === 'object') || false;
+  }
+
+  makeOption(item) {
+    if (this.isObject(item)) {
+      const { id, text, ...itemParams } = item;
+      return ();
+    }
+
+    return ();
+  }
+
+  render() {
+    const { data, value, ...props } = this.props;
+
+    delete props.options;
+    delete props.events;
+    delete props.onOpen;
+    delete props.onClose;
+    delete props.onSelect;
+    delete props.onChange;
+    delete props.onUnselect;
+
+    return (
+      
+    );
+  }
+}