public function bsListGroup($items, $listOptions=[], $defaultItemOptions=[], $listTagName='ul')
	{
		//prepare vars
		static::addCssClass($defaultItemOptions, 'list-group-item');
		$ret = '';

		//iterate over items
		foreach ($items as $i) {
			if (is_array($i)) {
				//validate content
				if (!isset($i['content'])) {
					throw new InvalidParamException('the index \'content\' is mandatory for each list element');
				}
				//prepare options
				$itemOptions = $defaultItemOptions;
				if (isset($i['options'])) {
					$itemOptions = ArrayHelper::merge($itemOptions, $i['options']);
					static::addCssClass($itemOptions, 'list-group-item');
				}
				//prepare url if necessary
				$isLink = isset($i['url']);
				if ($isLink) {
					$itemOptions['href'] = is_array($i['url']) ? UrlOriginal::to($i['url']) : $i['url'];
				}
				//bs type
				if (isset($i['type'])) {
					static::addCssClass($itemOptions, 'list-group-item-' . $i['type']);
				}
				//active
				if (isset($i['active'])) {
					$isActive = $i['active'] instanceof \Closure ? call_user_func($i['active']) : $i['active'];
					if ($isActive) static::addCssClass($itemOptions, 'active');
				}
				//badge
				if (isset($i['badgeVal'])) $i['content'] = static::bsBadge($i['badgeVal']) . $i['content'];
				//render item
				$ret .= static::tag($isLink ? 'a' : 'li', $i['content'], $itemOptions) . "\n";
			} else {
				$ret .= static::tag('li', $i, $defaultItemOptions);
			}
		}

		//enclose and return
		static::addCssClass($listOptions, 'list-group');
		return static::tag($listTagName, $ret, $listOptions);
	}