diff --git a/packages/option/README.md b/packages/option/README.md
new file mode 100644
index 000000000..2439420bb
--- /dev/null
+++ b/packages/option/README.md
@@ -0,0 +1,49 @@
+# LionOption
+
+[//]: # 'AUTO INSERT HEADER PREPUBLISH'
+
+`lion-option` is a selectable within a [lion-select-rich](../select-rich/)
+
+## Features
+
+- has checked state
+- has a modelValue
+- can be disabled
+- fully accessible
+
+## How to use
+
+### Installation
+
+```sh
+npm i --save @lion/select-rich
+```
+
+```js
+import '@lion/select-rich/lion-select-rich.js';
+import '@lion/select-rich/lion-options.js';
+import '@lion/option/lion-option.js';
+```
+
+### Example
+
+```html
+
+
+ Red
+ Hotpink
+
+
+```
+
+You can also set the full modelValue for each option.
+
+```html
+Red
+```
+
+For more details please see [lion-select-rich](../select-rich/).
diff --git a/packages/option/index.js b/packages/option/index.js
new file mode 100644
index 000000000..5a42f38df
--- /dev/null
+++ b/packages/option/index.js
@@ -0,0 +1 @@
+export { LionOption } from './src/LionOption.js';
diff --git a/packages/option/lion-option.js b/packages/option/lion-option.js
new file mode 100644
index 000000000..47a8282f3
--- /dev/null
+++ b/packages/option/lion-option.js
@@ -0,0 +1,3 @@
+import { LionOption } from './src/LionOption.js';
+
+customElements.define('lion-option', LionOption);
diff --git a/packages/option/package.json b/packages/option/package.json
new file mode 100644
index 000000000..5f7e1057a
--- /dev/null
+++ b/packages/option/package.json
@@ -0,0 +1,44 @@
+{
+ "name": "@lion/option",
+ "version": "0.0.0",
+ "description": "Allows to provide options for a rich select",
+ "author": "ing-bank",
+ "homepage": "https://github.com/ing-bank/lion/",
+ "license": "MIT",
+ "publishConfig": {
+ "access": "public"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/ing-bank/lion.git",
+ "directory": "packages/option"
+ },
+ "scripts": {
+ "prepublishOnly": "../../scripts/npm-prepublish.js"
+ },
+ "keywords": [
+ "lion",
+ "web-components",
+ "option"
+ ],
+ "main": "index.js",
+ "module": "index.js",
+ "files": [
+ "docs",
+ "src",
+ "stories",
+ "test",
+ "translations",
+ "*.js"
+ ],
+ "dependencies": {
+ "@lion/core": "^0.1.13",
+ "@lion/field": "^0.1.38",
+ "@lion/choice-input": "^0.2.18"
+ },
+ "devDependencies": {
+ "@open-wc/demoing-storybook": "^0.2.0",
+ "@open-wc/testing": "^2.0.6",
+ "sinon": "^7.2.2"
+ }
+}
diff --git a/packages/option/src/LionOption.js b/packages/option/src/LionOption.js
new file mode 100644
index 000000000..4d299b181
--- /dev/null
+++ b/packages/option/src/LionOption.js
@@ -0,0 +1,115 @@
+import { html, css, LitElement, DisabledMixin } from '@lion/core';
+import { FormRegisteringMixin } from '@lion/field';
+import { ChoiceInputMixin } from '@lion/choice-input';
+
+/**
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option
+ * Can be a child of datalist/select, or role="listbox"
+ *
+ * Element gets state supplied externally, reflects this to attributes,
+ * enabling SubClassers to style based on those states
+ */
+export class LionOption extends DisabledMixin(ChoiceInputMixin(FormRegisteringMixin(LitElement))) {
+ static get properties() {
+ return {
+ active: {
+ type: Boolean,
+ reflect: true,
+ },
+ };
+ }
+
+ static get styles() {
+ return [
+ css`
+ :host {
+ display: block;
+ background-color: white;
+ padding: 4px;
+ }
+
+ :host([active]) {
+ background-color: #ddd;
+ }
+
+ :host([checked]) {
+ background-color: #bde4ff;
+ }
+
+ :host([disabled]) {
+ color: #adadad;
+ }
+ `,
+ ];
+ }
+
+ constructor() {
+ super();
+ this.active = false;
+ this.__registerEventListener();
+ }
+
+ _requestUpdate(name, oldValue) {
+ super._requestUpdate(name, oldValue);
+
+ if (name === 'active') {
+ this.dispatchEvent(new Event('active-changed', { bubbles: true }));
+ }
+ }
+
+ updated(changedProperties) {
+ super.updated(changedProperties);
+ if (changedProperties.has('checked')) {
+ this.setAttribute('aria-selected', `${this.checked}`);
+ }
+
+ if (changedProperties.has('disabled')) {
+ this.setAttribute('aria-disabled', `${this.disabled}`);
+ }
+ }
+
+ render() {
+ return html`
+
+
+
+ `;
+ }
+
+ connectedCallback() {
+ super.connectedCallback();
+ this.setAttribute('role', 'option');
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback();
+ this.__unRegisterEventListeners();
+ }
+
+ __registerEventListener() {
+ this.__onClick = () => {
+ if (!this.disabled) {
+ this.checked = true;
+ }
+ };
+ this.__onMouseEnter = () => {
+ if (!this.disabled) {
+ this.active = true;
+ }
+ };
+ this.__onMouseLeave = () => {
+ if (!this.disabled) {
+ this.active = false;
+ }
+ };
+ this.addEventListener('click', this.__onClick);
+ this.addEventListener('mouseenter', this.__onMouseEnter);
+ this.addEventListener('mouseleave', this.__onMouseLeave);
+ }
+
+ __unRegisterEventListeners() {
+ this.removeEventListener('click', this.__onClick);
+ this.removeEventListener('mouseenter', this.__onMouseEnter);
+ this.removeEventListener('mouseleave', this.__onMouseLeave);
+ }
+}
diff --git a/packages/option/stories/index.stories.js b/packages/option/stories/index.stories.js
new file mode 100644
index 000000000..2df9de6ab
--- /dev/null
+++ b/packages/option/stories/index.stories.js
@@ -0,0 +1,35 @@
+import { storiesOf, html } from '@open-wc/demoing-storybook';
+
+import '../lion-option.js';
+
+storiesOf('Forms|Option', module)
+ .add(
+ 'States',
+ () => html`
+ Default
+ Disabled
+
+ With html
+ and multi Line
+
+ `,
+ )
+ .add(
+ 'Values',
+ () => html`
+ setting modelValue
+ setting modelValue active
+ setting modelValue checked
+ setting modelValue disabled
+ setting choiceValue
+ setting choiceValue active
+ setting choiceValue checked
+ setting choiceValue disabled
+ `,
+ );
diff --git a/packages/option/test/lion-option.test.js b/packages/option/test/lion-option.test.js
new file mode 100644
index 000000000..e034c586c
--- /dev/null
+++ b/packages/option/test/lion-option.test.js
@@ -0,0 +1,151 @@
+import { expect, fixture, html } from '@open-wc/testing';
+import sinon from 'sinon';
+
+import '../lion-option.js';
+
+describe('lion-option', () => {
+ describe('Values', () => {
+ it('has a modelValue', async () => {
+ const el = await fixture(html`
+
+ `);
+ expect(el.modelValue).to.deep.equal({ value: 10, checked: false });
+ });
+
+ it('can be checked', async () => {
+ const el = await fixture(html`
+
+ `);
+ expect(el.modelValue).to.deep.equal({ value: 10, checked: true });
+ });
+ });
+
+ describe('Accessibility', () => {
+ it('has the "option" role', async () => {
+ const el = await fixture(html`
+
+ `);
+ expect(el.getAttribute('role')).to.equal('option');
+ });
+
+ it('has "aria-selected" attribute when checked', async () => {
+ const el = await fixture(html`
+ Item 1
+ `);
+ expect(el.getAttribute('aria-selected')).to.equal('true');
+
+ el.checked = false;
+ // check that dom update is async
+ expect(el.getAttribute('aria-selected')).to.equal('true');
+
+ await el.updateComplete;
+ expect(el.getAttribute('aria-selected')).to.equal('false');
+ });
+
+ it('asynchronously adds the attributes "aria-disabled" and "disabled" when disabled', async () => {
+ const el = await fixture(html`
+ Item 1
+ `);
+ expect(el.getAttribute('aria-disabled')).to.equal('true');
+ expect(el.hasAttribute('disabled')).to.be.true;
+
+ el.disabled = false;
+ expect(el.getAttribute('aria-disabled')).to.equal('true');
+ expect(el.hasAttribute('disabled')).to.be.true;
+
+ await el.updateComplete;
+ expect(el.getAttribute('aria-disabled')).to.equal('false');
+ expect(el.hasAttribute('disabled')).to.be.false;
+ });
+ });
+
+ describe('State reflection', () => {
+ it('asynchronously adds the attribute "active" when active', async () => {
+ const el = await fixture(html`
+
+ `);
+ expect(el.active).to.equal(false);
+ expect(el.hasAttribute('active')).to.be.false;
+
+ el.active = true;
+ expect(el.active).to.be.true;
+ expect(el.hasAttribute('active')).to.be.false;
+ await el.updateComplete;
+ expect(el.hasAttribute('active')).to.be.true;
+
+ el.active = false;
+ expect(el.active).to.be.false;
+ expect(el.hasAttribute('active')).to.be.true;
+ await el.updateComplete;
+ expect(el.hasAttribute('active')).to.be.false;
+ });
+
+ it('does become active on [mouseenter]', async () => {
+ const el = await fixture(html`
+
+ `);
+ expect(el.active).to.be.false;
+ el.dispatchEvent(new Event('mouseenter'));
+ expect(el.active).to.be.true;
+ });
+
+ it('does become un-active on [mouseleave]', async () => {
+ const el = await fixture(html`
+
+ `);
+ expect(el.active).to.be.true;
+ el.dispatchEvent(new Event('mouseleave'));
+ expect(el.active).to.be.false;
+ });
+
+ it('does become checked on [click]', async () => {
+ const el = await fixture(html`
+
+ `);
+ expect(el.checked).to.be.false;
+ el.click();
+ await el.updateComplete;
+ expect(el.checked).to.be.true;
+ });
+
+ it('fires active-changed event', async () => {
+ const activeSpy = sinon.spy();
+ const el = await fixture(html`
+
+ `);
+ expect(activeSpy.callCount).to.equal(0);
+ el.active = true;
+ expect(activeSpy.callCount).to.equal(1);
+ });
+ });
+
+ describe('Disabled', () => {
+ it('does not becomes active on [mouseenter]', async () => {
+ const el = await fixture(html`
+
+ `);
+ expect(el.active).to.be.false;
+ el.dispatchEvent(new Event('mouseenter'));
+ expect(el.active).to.be.false;
+ });
+
+ it('does not become checked on [click]', async () => {
+ const el = await fixture(html`
+
+ `);
+ expect(el.checked).to.be.false;
+ el.click();
+ await el.updateComplete;
+ expect(el.checked).to.be.false;
+ });
+
+ it('does not become un-active on [mouseleave]', async () => {
+ const el = await fixture(html`
+
+ `);
+ expect(el.active).to.be.true;
+ el.dispatchEvent(new Event('mouseleave'));
+ expect(el.active).to.be.true;
+ });
+ });
+});
diff --git a/packages/select-rich/README.md b/packages/select-rich/README.md
new file mode 100644
index 000000000..4c444798b
--- /dev/null
+++ b/packages/select-rich/README.md
@@ -0,0 +1,79 @@
+# Select Rich
+
+[//]: # 'AUTO INSERT HEADER PREPUBLISH'
+
+`lion-select-rich` component is a 'rich' version of the native `