{"id":15024281,"url":"https://github.com/stevdza-san/kotlinbootstrap","last_synced_at":"2025-04-04T08:03:30.807Z","repository":{"id":190131307,"uuid":"681960054","full_name":"stevdza-san/KotlinBootstrap","owner":"stevdza-san","description":"Use the official Bootstrap UI components with Kotlin and Compose HTML, to build a frontend on the web. ","archived":false,"fork":false,"pushed_at":"2024-11-18T12:05:26.000Z","size":22465,"stargazers_count":216,"open_issues_count":7,"forks_count":15,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-04T07:29:02.981Z","etag":null,"topics":["bootstrap","bootstrap5","compose-html","frontend","jetpack-compose","kobweb","kotlin","web"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stevdza-san.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-23T06:20:40.000Z","updated_at":"2025-03-29T06:32:52.000Z","dependencies_parsed_at":"2024-12-13T19:10:12.590Z","dependency_job_id":"97e5de90-3df9-409e-aa66-fc99f999f0cd","html_url":"https://github.com/stevdza-san/KotlinBootstrap","commit_stats":{"total_commits":131,"total_committers":3,"mean_commits":"43.666666666666664","dds":0.03816793893129766,"last_synced_commit":"4393c25380bad6f2c0b91b57c08d24a8c5b97000"},"previous_names":["stevdza-san/kotlinbootstrap"],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevdza-san%2FKotlinBootstrap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevdza-san%2FKotlinBootstrap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevdza-san%2FKotlinBootstrap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevdza-san%2FKotlinBootstrap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stevdza-san","download_url":"https://codeload.github.com/stevdza-san/KotlinBootstrap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247142059,"owners_count":20890652,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bootstrap","bootstrap5","compose-html","frontend","jetpack-compose","kobweb","kotlin","web"],"created_at":"2024-09-24T20:00:03.897Z","updated_at":"2025-04-04T08:03:30.781Z","avatar_url":"https://github.com/stevdza-san.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"#\"\u003e\n    \u003cimg src=\"/ASSETS/logo.svg\" alt=\"Kotlin-Bootstrap logo\" width=\"200\" height=\"165\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003ch3 align=\"center\"\u003eKotlin Bootstrap\u003c/h3\u003e\n\u003cp\u003e\n  ⚡Highly experimental library built on top of the \u003ca href=\"https://github.com/varabyte/kobweb\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eKobweb\u003c/a\u003e (Compose HTML framework). It allows you to use the official \u003ca href=\"https://getbootstrap.com/\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eBootstrap\u003c/a\u003e UI components with Kotlin and Jetpack Compose, to build a frontend on the web. You are required to use the kobweb framework, otherwise it won't work. At the moment, components are not yet fully customizable, but I'll work on it. ⚽ The goal is to release all bootstrap components, and only then work on it's customization furthermore. Silk UI layer which is included with Kobweb is not required for this library to work.\n\u003c/p\u003e\n\n## Available Components\n- [Button](#button)\n- [IconButton](#iconbutton)\n- [Input](#input)\n- [Dropdown](#dropdown)\n- [TextArea](#textarea)\n- [Checkbox](#checkbox)\n- [RadioButton](#radiobutton)\n- [Switch](#switch)\n- [Alert](#alert)\n- [Toast](#toast)\n- [Modal](#modal)\n- [Select](#select)\n- [Range](#range)\n- [Progress](#progress)\n- [Spinner](#spinner)\n- [Tooltip](#tooltip)\n- [Collapse](#collapse)\n- [Carousel](#carousel)\n- [Breadcrumb](#breadcrumb)\n- [Accordion](#accordion)\n- [NavBar](#navbar)\n- [Offcanvas](#offcanvas)\n- [Badge](#badge)\n- [CloseButton](#closebutton)\n- [ColorPicker](#colorpicker)\n- [FilePicker](#filepicker)\n- [Pagination](#pagination)\n\n## Bootstrap Icons usage\n- [Icons](#icons)\n\n## Install\nUpdate a Project level `build.gradle.kts` file:\n\n```gradle\nrepositories {\n    ..\n    maven(url = \"https://jitpack.io\")\n}\n```\n\nUpdate a `site` module `build.gradle.kts` file:\n\n```gradle\nkotlin { \n    sourceSets {\n        ..\n        val jsMain by getting {\n            dependencies {\n                ..\n                implementation(\"com.github.stevdza-san:KotlinBootstrap:0.1.5\")\n            }\n        }\n    }\n}\n```\n\n## Button\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/buttons.png\" alt=\"Buttons Preview\" width=\"812\"\u003e\n\u003c/p\u003e \n\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/loadingButton.gif?raw=true\" width=\"268\"/\u003e\n  \u003cimg src=\"/ASSETS/loadingButtonText.gif?raw=true\" width=\"268\"/\u003e\n    \u003cimg src=\"/ASSETS/badgeButton.gif?raw=true\" width=\"268\"/\u003e\n\u003c/p\u003e\n\n\u003cp\u003eA simple button usage:\u003c/p\u003e\n\n```kotlin\nBSButton(\n    text = \"Sign in\",\n    onClick = {}\n)\n```\n\n\u003cp\u003eYou can update your button state to loading, as well as specify the exact Loading Text \u003cem\u003e(optional)\u003c/em\u003e:\u003c/p\u003e\n\n```kotlin\nvar buttonLoading by remember { mutableStateOf(false) }\nBSButton(\n    text = \"Sign in\",\n    loading = buttonLoading,\n    loadingText = \"Please wait...\",\n    onClick = { buttonLoading = true }\n)\n```\n\n\u003cp\u003eAdd a Badge to your button:\u003c/p\u003e\n\n```kotlin\nBSButton(\n    text = \"Shopping Cart\",\n    badge = ButtonBadge(\n        text = \"10\"\n    ),\n    onClick = {}\n)\n```\n\n\u003cp\u003eButtons with custom properties.\u003c/p\u003e\n\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/custombuttons.gif?raw=true\" alt=\"CustomButtons Preview\" width=\"812\"\u003e\n\u003c/p\u003e \n\n```kotlin\nColumn(modifier = Modifier.gap(20.px).fillMaxSize()) {\n    Row(modifier = Modifier.gap(12.px)) {\n        BSButton(\n            text = \"Apply Now\",\n            customization = ButtonCustomization(\n                color = Colors.White,\n                hoverColor = Colors.White,\n                backgroundColor = Colors.Black,\n                hoverBackgroundColor = rgba(0, 0, 0, 0.8),\n                fontFamily = \"Space Grotesk\"\n            ),\n            onClick = {}\n        )\n        BSButton(\n            text = \"Get Started\",\n            customization = ButtonCustomization(\n                color = Colors.White,\n                hoverColor = Colors.White,\n                activeColor = Colors.WhiteSmoke,\n                borderColor = Colors.White,\n                hoverBorderColor = Colors.White,\n                activeBorderColor = rgb(168, 192, 255),\n                gradient = linearGradient(\n                    from = rgb(168, 192, 255),\n                    to = rgb(63, 43, 150),\n                    dir = LinearGradient.Direction.ToTopRight\n                ),\n                borderRadius = BSBorderRadius(all = 50.px),\n                horizontalPadding = 1.25.cssRem\n            ),\n            onClick = {}\n        )\n    }\n    Row(modifier = Modifier.gap(12.px)) {\n        BSButton(\n            text = \"Submit\",\n            customization = ButtonCustomization(\n                color = Colors.White,\n                hoverColor = Colors.Wheat,\n                activeColor = Colors.White,\n                borderColor = Colors.White,\n                hoverBorderColor = Colors.Wheat,\n                activeBorderColor = Colors.White,\n                gradient = linearGradient(\n                    from = rgb(188, 78, 156),\n                    to = rgb(248, 7, 89),\n                    dir = LinearGradient.Direction.ToTopRight\n                ),\n                borderRadius = BSBorderRadius(topLeft = 20.px, bottomRight = 20.px),\n                fontFamily = \"Rubik\"\n            ),\n            onClick = {}\n        )\n    }\n}\n```\n\n## IconButton\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/iconbutton.gif?raw=true\" alt=\"IconButtons Preview\"\u003e\n\u003c/p\u003e \n\n`BSIconButton` is a component used to display a Bootstrap Icon (`BSIcons`) inside a button. You can customize similar properties like with a regular `BSButton` as well.\nA basic usage:\n\n```kotlin\nColumn(modifier = Modifier.gap(20.px).fillMaxSize()) {\n    Row(modifier = Modifier.gap(12.px)) {\n        BSIconButton(\n            icon = BSIcons.UPLOAD,\n            onClick = {}\n        )\n        BSIconButton(\n            icon = BSIcons.UPLOAD,\n            variant = ButtonVariant.PrimaryOutline,\n            onClick = {}\n        )\n    }\n    Row(modifier = Modifier.gap(12.px)) {\n        BSIconButton(\n            icon = BSIcons.ANDROID,\n            variant = ButtonVariant.Success,\n            onClick = {}\n        )\n        BSIconButton(\n            icon = BSIcons.ANDROID,\n            variant = ButtonVariant.SuccessOutline,\n            onClick = {}\n        )\n    }\n}\n```\n\n## Input\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/inputs.gif?raw=true\" alt=\"Inputs Preview\" width=\"360\"\u003e\n\u003c/p\u003e \n\n\u003cp\u003eA simple usage with a placeholder:\u003c/p\u003e\n\n```kotlin\nvar inputValue by remember { mutableStateOf(\"\") }\nBSInput(\n    value = inputValue,\n    placeholder = \"Type here\",\n    onValueChange = {\n        inputValue = it\n    }\n)\n```\n\n\u003cp\u003eFloating style input field, where a label is animated:\u003c/p\u003e\n\n```kotlin\nBSInput(\n    value = inputValue,\n    label = \"Email Address\",\n    floating = true,\n    onValueChange = {}\n)\n```\n\n\u003cp\u003ePositive validation style input field:\u003c/p\u003e\n\n```kotlin\nBSInput(\n    value = inputValue,\n    label = \"Email Address\",\n    placeholder = \"Type here\",\n    validation = InputValidation(\n      isValid = true\n    ),\n    onValueChange = {}\n)\n```\n\n\u003cp\u003eNegative validation style input field:\u003c/p\u003e\n\n```kotlin\nBSInput(\n    value = inputValue,\n    label = \"Email Address\",\n    placeholder = \"Type here\",\n    validation = InputValidation(\n      isInvalid = true\n    ),\n    onValueChange = {}\n)\n```\n\n\u003cp\u003eDisabled input field:\u003c/p\u003e\n\n```kotlin\nBSInput(\n    value = inputValue,\n    label = \"Email Address\",\n    placeholder = \"Type here\",\n    disabled = true,\n    onValueChange = {}\n)\n```\n\n\u003cp\u003ePlain text input field:\u003c/p\u003e\n\n```kotlin\nBSInput(\n    value = inputValue,\n    label = \"Email Address\",\n    placeholder = \"Type here\",\n    plainText = true,\n    onValueChange = {}\n)\n```\n\n## Dropdown\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/dropdowns.png\" alt=\"Dropdown Preview\" width=\"812\"\u003e\n\u003c/p\u003e \n\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/placeholderDropdown.gif?raw=true\" width=\"268\"/\u003e\n  \u003cimg src=\"/ASSETS/darkBackgroundDropdown.gif?raw=true\" width=\"268\"/\u003e\n    \u003cimg src=\"/ASSETS/disabledDropdown.gif?raw=true\" width=\"268\"/\u003e\n\u003c/p\u003e\n\n\u003cp\u003eDropdown with a placeholder:\u003c/p\u003e\n\n```kotlin\nBSDropdown(\n    placeholder = \"Select a Platform\",\n    items = listOf(\"Android\", \"iOS\", \"Web\"),\n    onItemSelect = { index, value -\u003e }\n)\n```\n\n\u003cp\u003eDropdown with a dark background:\u003c/p\u003e\n\n```kotlin\nBSDropdown(\n    items = listOf(\"Android\", \"iOS\", \"Web\"),\n    darkBackground = true,\n    onItemSelect = { index, value -\u003e }\n)\n```\n\n\u003cp\u003eDisabled Dropdown item:\u003c/p\u003e\n\n```kotlin\nBSDropdown(\n    items = listOf(\"Android\", \"iOS\", \"Web\"),\n    disabledItems = listOf(\"iOS\"),\n    onItemSelect = { index, value -\u003e }\n)\n```\n\n## TextArea\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/textarea.gif?raw=true\" alt=\"TextArea Preview\" width=\"460\"\u003e\n\u003c/p\u003e \n\n\n\u003cp\u003eBasic TextArea example with a label:\u003c/p\u003e\n\n```kotlin\nvar value by remember { mutableStateOf(\"\") }\nBSTextArea(\n    value = value,\n    label = \"Email Address\",\n    placeholder = \"Type here...\",\n    onValueChange = { value = it }\n)\n```\n\n\u003cp\u003eFloating TextArea:\u003c/p\u003e\n\n```kotlin\nvar value by remember { mutableStateOf(\"\") }\nBSTextArea(\n    value = value,\n    label = \"Email Address\",\n    floating = true,\n    onValueChange = { value = it }\n)\n```\n\n## Checkbox\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/checkboxes.gif?raw=true\" alt=\"Checkboxes Preview\" width=\"280\"\u003e\n\u003c/p\u003e \n\n\u003cp\u003eBasic Checkbox usage:\u003c/p\u003e\n\n```kotlin\nBSCheckbox(\n    label = \"Kotlin\",\n    onClick = {}\n)\n```\n\n\u003cp\u003eReversed order checkbox:\u003c/p\u003e\n\n```kotlin\nBSCheckbox(\n    label = \"C++\",\n    reverse = true,\n    onClick = {}\n)\n```\n\n\u003cp\u003eToggle button style checkbox:\u003c/p\u003e\n\n```kotlin\nBSCheckbox(\n    label = \"Python\",\n    toggleButton = true,\n    onClick = {}\n)\n```\n\n## RadioButton\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/radiobuttons.gif?raw=true\" alt=\"RadioButtons Preview\"\u003e\n\u003c/p\u003e \n\n\u003cp\u003eBasic RadioButtonGroup usage:\u003c/p\u003e\n\n```kotlin\nBSRadioButtonGroup {\n    BSRadioButton(label = \"Android\", onClick = {})\n    BSRadioButton(label = \"iOS\", onClick = {})\n    BSRadioButton(label = \"Web\", onClick = {})\n}\n```\n\n\u003cp\u003eRadioButtonGroup in a horizontal orientation:\u003c/p\u003e\n\n```kotlin\nBSRadioButtonGroup(inline = true) {\n    BSRadioButton(label = \"Android\", onClick = {})\n    BSRadioButton(label = \"iOS\", onClick = {})\n    BSRadioButton(label = \"Web\", onClick = {})\n}\n```\n\n\u003cp\u003eToggleButton style of a RadioButtonGroup:\u003c/p\u003e\n\n```kotlin\nBSRadioButtonGroup(toggleButton = true) {\n    BSRadioButton(label = \"Android\", onClick = {})\n    BSRadioButton(label = \"iOS\", onClick = {})\n    BSRadioButton(label = \"Web\", onClick = {})\n}\n```\n\n## Switch\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/switches.gif?raw=true\" alt=\"Switches Preview\" width=\"700\"\u003e\n\u003c/p\u003e \n\n\u003cp\u003eSwitch with a default checked state:\u003c/p\u003e\n\n```kotlin\nBSSwitch(\n    label = \"Android\",\n    defaultChecked = true,\n    onClick = {}\n)\n```\n\n\u003cp\u003eDisabled Switch with a default unchecked state:\u003c/p\u003e\n\n```kotlin\nBSSwitch(\n    label = \"Android\",\n    disabled = true,\n    onClick = {}\n)\n```\n\n## Alert\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/alerts.gif?raw=true\" alt=\"Alerts Preview\" width=\"420\"\u003e\n\u003c/p\u003e \n\n\u003cp\u003ePrimary Style Alert with an Info icon and a bold text:\u003c/p\u003e\n\n```kotlin\nBSAlert(\n    message = \"Visit my YouTube Channel: Stevdza-San\",\n    icon = AlertIcon.Info,\n    bold = \"Stevdza-San\"\n)\n```\n\n\u003cp\u003eSuccess Style Alert with a Checkmark icon and a link text:\u003c/p\u003e\n\n```kotlin\nBSAlert(\n    message = \"You have successfully purchased a book!\",\n    alertLink = Pair(\"book\", \"https://google.com\"),\n    icon = AlertIcon.Checkmark,\n    style = AlertStyle.Success\n)\n```\n\n\u003cp\u003eDismissable Alert:\u003c/p\u003e\n\n```kotlin\nBSAlert(\n    message = \"Dismissable Alert.\",\n    dismissible = true,\n    style = AlertStyle.Dark\n)\n```\n\n## Toast\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/toast.gif?raw=true\" alt=\"Taosts Preview\"\u003e\n\u003c/p\u003e \n\nEven though a Toast component is not yet fully customizable, from this preview above you can see that there are different variations and styles that you can apply to it. For triggering a Toast component, you do need to call a special function `showToast(toastId)` and pass your toast id, in order to properly display it on the screen. Every Toast components needs to be wrapped inside the `BSToastGroup` composable. Also there's a `ToastPlacement` parameter available on `BSToastGroup` that you can use to modify a toast placement.\n\n`BSToast` gets visible once you trigger a `showToast()` function:\n\n```kotlin\nBSToastGroup {\n    BSToast(\n        id = \"toast\",\n        title = \"Welcome\",\n        body = \"Browse our website for more interesting products!\",\n        onCloseClick = {}\n    )\n}\n\nBSButton(\n    text = \"Show Toast\",\n    onClick = {\n        showToast(\"toast\")\n    }\n)\n```\n\n`BSToastBasic` which is not automatically dismissable, because it has `autoHide` parameter equal to false:\n\n```kotlin\nBSToastGroup {\n    BSToastBasic(\n        id = \"toastBasic\",\n        text = \"Thank you for your feedback!\",\n        style = ToastStyle.Dark,\n        autoHide = false,\n        closeButtonDark = false,\n        onCloseClick = {}\n    )\n}\n```\n\n`BSToastAction` which contains additional positive/negative buttons:\n\n```kotlin\nBSToastGroup {\n    BSToastAction(\n        id = \"toastAction2\",\n        text = \"Are you sure you want to delete 24 items?\",\n        positiveButtonText = \"Yes\",\n        positiveButtonVariant = ButtonVariant.Primary,\n        negativeButtonVariant = ButtonVariant.Danger,\n        negativeButtonText = \"Cancel\",\n        style = ToastStyle.Dark,\n        onPositiveButtonClick = {},\n        onNegativeButtonClick = {}\n    )\n}\n```\n\n## Modal\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/modal.gif?raw=true\" alt=\"Modal Preview\" width=\"560\"\u003e\n\u003c/p\u003e \n\n`BSModal` component is not visible by default. If you want to show it on your page, then you need to call a modifier `showModalOnClick()` on a `BSButton` or any other clickable composable, and pass the ID of the modal itself. After you do that, just click the component that has that modifier, and your `BSModal` will appear.\n\n\u003cp\u003eA basic Modal usage:\u003c/p\u003e\n\n```kotlin\nBSModal(\n    id = \"contactModal\",\n    title = \"Contact us\",\n    body = {\n        Column {\n            BSInput(\n                modifier = Modifier\n                  .fillMaxWidth()\n                  .margin(bottom = 14.px),\n                value = \"\",\n                label = \"Email Address\",\n                placeholder = \"Type here...\",\n                onValueChange = {}\n            )\n            BSTextArea(\n                modifier = Modifier.fillMaxWidth(),\n                value = \"\",\n                label = \"Message\",\n                placeholder = \"Type here...\",\n                onValueChange = {}\n            )\n        }\n    },\n    positiveButtonText = \"Send Message\",\n    negativeButtonText = \"Close\",\n    onPositiveButtonClick = {},\n    onNegativeButtonClick = {}\n)\n\nBSButton(\n    modifier = Modifier.showModalOnClick(id = \"contactModal\"),\n    text = \"Trigger\",\n    onClick = {}\n)\n```\n\n## Select\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/select.gif?raw=true\" alt=\"Select Preview\" width=\"360\"\u003e\n\u003c/p\u003e \n\n\u003cp\u003eSelect component's basic usage:\u003c/p\u003e\n\n```kotlin\nBSSelect(\n    items = listOf(\"Android\", \"iOS\", \"Web\", \"Desktop\"),\n    placeholder = \"Choose a Platform\",\n    onItemSelected = { index, value -\u003e }\n)\n```\n\n\u003cp\u003eFloating style of a Select component:\u003c/p\u003e\n\n```kotlin\nBSSelect(\n    items = listOf(\"Android\", \"iOS\", \"Web\", \"Desktop\"),\n    placeholder = \"Choose a Platform\",\n    floating = true,\n    onItemSelected = { index, value -\u003e }\n)\n```\n\n## Range\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/range.gif?raw=true\" alt=\"Range Preview\" width=\"450\"\u003e\n\u003c/p\u003e \n\n\u003cp\u003eRange's basic usage:\u003c/p\u003e\n\n```kotlin\nBSRange(\n    modifier = Modifier.width(300.px),\n    label = \"Range (0-10)\",\n    min = 0,\n    max = 10,\n    onSelect = {}\n)\n```\n\n## Progress\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/progress.gif?raw=true\" alt=\"Progress Preview\" width=\"360\"\u003e\n\u003c/p\u003e \n\n\u003cp\u003eBasic Progress component usage:\u003c/p\u003e\n\n```kotlin\nBSProgress(percentage = 85.percent)\n```\n\n\u003cp\u003eStripped style:\u003c/p\u003e\n\n```kotlin\nBSProgress(\n  percentage = 85.percent,\n  striped = true\n)\n```\n\n\u003cp\u003eAnimated Stripped style:\u003c/p\u003e\n\n```kotlin\nBSProgress(\n  percentage = 85.percent,\n  stripedAnimated = true\n)\n```\n\n\n## Spinner\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/spinner.gif?raw=true\" alt=\"Spinner Preview\" width=\"600\"\u003e\n\u003c/p\u003e \n\n\u003cp\u003eDefault Spinner style:\u003c/p\u003e\n\n```kotlin\nBSSpinner(variant = SpinnerVariant.Default)\n```\n\n\u003cp\u003eGrow Spinner style:\u003c/p\u003e\n\n```kotlin\nBSSpinner(variant = SpinnerVariant.DefaultGrow)\n```\n\n## Tooltip\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/tooltip.gif?raw=true\" alt=\"Tooltip Preview\"\u003e\n\u003c/p\u003e \n\nBefore you can use and display a Tooltip, you need to initialize them by calling `initializeTooltips()` function:\n\n```kotlin\nLaunchedEffect(Unit) {\n    initializeTooltips()\n}\n```\n\nUsually, the content on top of which you want to add a tooltip, is specified as a content lambda of the `BSTooltip` composable:\n\n```kotlin\nBSTooltip(\n    text = \"https://stevdza-san.com\",\n    content = {\n        A(href = \"https://stevdza-san.com\") {\n            SpanText(text = \"Online Courses\")\n        }\n    }\n)\n```\n\nYou can also change a direction of the tooltip, by using `TooltipDirection` parameter:\n\n```kotlin\nBSTooltip(\n    text = \"https://stevdza-san.com\",\n    direction = TooltipDirection.Right,\n    content = {\n        A(href = \"https://stevdza-san.com\") {\n            SpanText(text = \"Online Courses\")\n        }\n    }\n)\n```\n\n## Collapse\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/collapse.gif?raw=true\" alt=\"Collapse Preview\" width=\"500\"\u003e\n\u003c/p\u003e \n\nTo make your button or any other clickable component as the one that triggers the `BSCollapse`, you need to add a `.showCollapse(id)` modifier and pass the `BSCollapse` id.\n\n```kotlin\nColumn(\n    modifier = Modifier.width(400.px),\n    horizontalAlignment = Alignment.CenterHorizontally\n) {\n    BSButton(\n        modifier = Modifier\n            .alignContent(AlignContent.Center)\n            .showCollapse(id = \"collapse1\"),\n        text = \"FAQ\",\n        onClick = {}\n    )\n    BSCollapse(id = \"collapse1\") {\n        Column(modifier = Modifier.margin(top = 14.px)) {\n            SpanText(\n                modifier = Modifier\n                    .fontSize(18.px)\n                    .fontWeight(FontWeight.Bold),\n                text = \"1. How long does the course take to complete?\"\n            )\n            SpanText(\n                text = \"\"\"\n                      The course is self-paced, so you can complete it at your own speed.\n                      On average, most students finish the course in about 3-6 weeks, \n                      depending on the time they can dedicate to learning.\n                \"\"\".trimIndent()\n            )\n        }\n    }\n}\n```\n\n## Carousel\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/carousel.gif?raw=true\" alt=\"Carousel Preview\" width=\"700\"\u003e\n\u003c/p\u003e \n\nA basic usage of Carousel component:\n\n```kotlin\nBSCarousel(\n    items = listOf(\n        CarouselItem(\n            image = \"https://images.pexels.com/photos/2662116/pexels-photo-2662116.jpeg?auto=compress\u0026cs=tinysrgb\u0026w=1260\u0026h=750\u0026dpr=1\",\n            title = \"Moraine Lake\"\n        ),\n        CarouselItem(\n            image = \"https://images.pexels.com/photos/147411/italy-mountains-dawn-daybreak-147411.jpeg?auto=compress\u0026cs=tinysrgb\u0026w=1260\u0026h=750\u0026dpr=1\",\n            title = \"Italy\"\n        ),\n        CarouselItem(\n            image = \"https://images.pexels.com/photos/1166209/pexels-photo-1166209.jpeg?auto=compress\u0026cs=tinysrgb\u0026w=1260\u0026h=750\u0026dpr=1\",\n            title = \"Lavender\"\n        ),\n    ),\n    width = 900.px,\n    height = 500.px\n)\n```\n\n## Breadcrumb\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/breadcrumb.gif?raw=true\" alt=\"Breadcrumb Preview\"\u003e\n\u003c/p\u003e \n\nYou can specify and replace a default `divider` parameter to change a separator string, and also you can set a currently selected `BreadcrumbItem` as well.\n\n```kotlin\nBSBreadcrumb(\n    items = listOf(\n        BreadcrumbItem(\n            text = \"Home\",\n            href = \"#\"\n        ),\n        BreadcrumbItem(\n            text = \"Pricing\",\n            href = \"#\"\n        ),\n        BreadcrumbItem(\n            text = \"Services\",\n            href = \"#\"\n        ),\n        BreadcrumbItem(\n            text = \"About\",\n            href = \"#\"\n        ),\n        BreadcrumbItem(\n            text = \"Contact us\",\n            href = \"#\"\n        )\n    ),\n    divider = \"\u003e\",\n    currentItem = \"About\"\n)\n```\n\n## Accordion\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/accordion.gif?raw=true\" alt=\"Accordion Preview\" width=\"500\"\u003e\n\u003c/p\u003e \n\nYou can customize it's `flush` parameter which will remove some borders and rounded corners to render accordions edge-to-edge with their parent container. `alwaysOpen` parameter will make accordion items stay open when another item is opened.\n\n\u003cp\u003eBasic Accordion example:\u003c/p\u003e\n\n```kotlin\nBSAccordion(\n    modifier = Modifier.width(300.px),\n    items = listOf(\n        AccordionItem(\n            title = \"Step 01: Identify your goals\",\n            content = { SpanText(text = \"Body text here...\") },\n            defaultOpened = true\n        ),\n        AccordionItem(\n            title = \"Step 02: Write your goals\",\n            content = {  SpanText(text = \"Body text here...\")}\n        ),\n        AccordionItem(\n            title = \"Step 03: Analysis\",\n            content = {  SpanText(text = \"Body text here...\")}\n        ),\n        AccordionItem(\n            title = \"Step 04: Objectives\",\n            content = { SpanText(text = \"Body text here...\")}\n        )\n    )\n)\n```\n\n## NavBar\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/navbar.gif?raw=true\" alt=\"NavBar Preview\"\u003e\n\u003c/p\u003e \n\nThe NavBar typically appears at the top of the web page and contains various navigation elements such as links, buttons, dropdown menus, and branding elements like logos or site names. It adapts to different screen sizes and devices, making it ideal for responsive web design.\n\n```kotlin\nBSNavBar(\n    modifier = Modifier.fillMaxWidth(),\n    stickyTop = true,\n    itemsAlignment = Alignment.CenterHorizontally,\n    brand = NavBarBrand(\n        title = \"KotlinBootstrap\",\n        image = \"https://getbootstrap.com/docs/5.3/assets/brand/bootstrap-logo.svg\",\n        href = \"#\"\n    ),\n    expand = NavBarExpand.LG,\n    backgroundStyle = BackgroundStyle.Dark,\n    items = listOf(\n        NavLink(\n            id = \"homeLink\",\n            title = \"Home\",\n            onClick = {\n                println(\"Index: $it Title: Home\")\n            }   \n        ),\n        NavLink(\n            id = \"servicesLink\",\n            title = \"Services\",\n            onClick = {}\n        ),\n        NavLink(\n            id = \"pricingLink\",\n            title = \"Pricing\",\n            onClick = {}\n        ),\n        NavLink(\n            id = \"aboutLink\",\n            title = \"About us\",\n            onClick = {}\n        ),\n        NavDropdown(\n            placeholder = \"Language\",\n            items = listOf(\n                NavDropdownItem(\n                    id = \"kotlinLanguage\",\n                    title = \"Kotlin\",\n                    onClick = {\n                        println(\"Index: $it Title: Kotlin\")\n                    }\n                ),\n                NavDropdownItem(\n                    id = \"javaLanguage\",\n                    title = \"Java\",\n                    onClick = {}\n                )\n            )\n        )\n    ),\n    inputField = NavBarInputField(\n        placeholder = \"Search\",\n        value = \"\",\n        onValueChange = {}\n    ),\n    button = NavBarButton(\n        text = \"Search\",\n        onClick = {}\n    )\n)\n```\n\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/navbar2.gif?raw=true\" alt=\"NavBar Preview\"\u003e\n\u003c/p\u003e \n\nYou can add an extra parameter, to replace a default expandable menu with an `Offcanvas` side bar:\n```kotlin\nBSNavBar(\n    ..\n    offcanvas = NavBarOffcanvas(\n        id = \"myOffcanvas\",\n        title = \"KotlinBootstrap\",\n        dark = true\n    )\n    ..\n)\n```\n\n## Offcanvas\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/offcanvas.gif?raw=true\" alt=\"Offcanvas Preview\"\u003e\n\u003c/p\u003e \n\nOffcanvas is used to create sidebar or panel that can slide in and out of the viewport. This component is often used to display additional content, navigation menus, or options without taking up the entire screen space.\n\n```kotlin\nval links = listOf(\"Home\", \"Pricing\", \"Services\", \"Contact us\")\nBSOffcanvas(\n    id = \"myOffCanvas\",\n    title = \"Welcome!\",\n    body = {\n        Column {\n            links.forEach { name -\u003e\n                A(\n                    attrs = Modifier\n                        .margin(bottom = 16.px)\n                        .textDecorationLine(TextDecorationLine.None)\n                        .cursor(Cursor.Pointer)\n                        .toAttrs()\n                ) {\n                    SpanText(name)\n                }\n            }\n            BSButton(\n            text = \"Sign in\",\n            onClick = {}\n            )\n        }\n    },\n    placement = OffcanvasPlacement.END\n)\n\nColumn(\n    modifier = Modifier.fillMaxSize(),\n    verticalArrangement = Arrangement.Center,\n    horizontalAlignment = Alignment.CenterHorizontally\n) {\n    BSButton(\n        modifier = Modifier.showOffcanvasOnClick(id = \"myOffCanvas\"),\n        text = \"Show\",\n        onClick = {}\n    )\n}\n```\n\n## Badge\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/badge.png\" alt=\"Badge Preview\"\u003e\n\u003c/p\u003e \n\nThere are four different `BadgeVariant`'s: Straight, Regular, Rounded, Empty. You can customize the `BackgroundStyle` of the badge, a `fontFamily`, `fontSize`, and `fontWeight` as well.\n\n```kotlin\nRow(verticalAlignment = Alignment.CenterVertically) {\n    SpanText(\n        modifier = Modifier.margin(right = 8.px),\n        text = \"Fitness Tracker\"\n    )\n    BSBadge(\n        modifier = Modifier.margin(bottom = 8.px),\n        text = \"New\",\n        variant = BadgeVariant.Straight\n    )\n}\n```\n\n## CloseButton\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/closebutton.gif?raw=true\" alt=\"CloseButton Preview\"\u003e\n\u003c/p\u003e \n\nA basic usage:\n\n```kotlin\nBSCloseButton()\n```\n\n## ColorPicker\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/colorpicker.gif?raw=true\" alt=\"ColorPicker Preview\"\u003e\n\u003c/p\u003e \n\nA basic usage:\n\n```kotlin\nBSColorPicker(onColorSelected = {})\n```\n\n## FilePicker\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/filepicker.gif?raw=true\" alt=\"FilePicker Preview\"\u003e\n\u003c/p\u003e \n\nFilePicker component provides a required lambda `onFileSelected`, that returns two strings. The first one represents a fileName, while the second one the actual file encoded in BASE_64 string.\n\nA basic usage:\n\n```kotlin\nBSFileInput(\n    label = \"Choose a file\",\n    onFileSelected = { fileName, file -\u003e }\n)\n```\n\n## Pagination\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/pagination.gif?raw=true\" alt=\"Pagination Preview\"\u003e\n\u003c/p\u003e \n\n`BSPagination` component is used to divide long lists or tables into multiple pages, making it easier for users to navigate through the content.\n\nA basic usage:\n\n```kotlin\nvar currentPage by remember { mutableStateOf(1) }\n\nBSPagination(\n    pages = 15,\n    maxVisiblePages = 3,\n    currentPage = currentPage,\n    previousButton = PreviousButton(\n        onClick = { currentPage = it }\n    ),\n    nextButton = NextButton(\n        onClick = { currentPage = it }\n    ),\n    onPageClick = { currentPage = it }\n)\n```\n\n## Icons\nThere are over 2.000 icons available in a Bootstrap library. You can use a `BSIcons` object to access all icons. There's a `BSIcon` composable function that allows you to display those same icons as well. There's also a `BSIconButton` composable that displays an icon inside the button.\n\nExample *(Zoomed in)* icon, that represents one of the many vector icons in the library:\n\n```kotlin\nBSIcon(\n  icon = BSIcons.ANDROID,\n  size = 1.cssRem,\n  color = Colors.LightGreen\n)\n```\n\n\u003cp\u003e\n  \u003cimg src=\"/ASSETS/androidIcon.png\" alt=\"Android Icon Preview\"\u003e\n\u003c/p\u003e \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstevdza-san%2Fkotlinbootstrap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstevdza-san%2Fkotlinbootstrap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstevdza-san%2Fkotlinbootstrap/lists"}