diff --git a/frontend/src/app/main/ui/ds.cljs b/frontend/src/app/main/ui/ds.cljs
index 9ac05d4f88..85268cf8d2 100644
--- a/frontend/src/app/main/ui/ds.cljs
+++ b/frontend/src/app/main/ui/ds.cljs
@@ -8,6 +8,7 @@
(:require
[app.main.ui.ds.buttons.button :refer [button*]]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
+ [app.main.ui.ds.forms.input :refer [input*]]
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]]
[app.main.ui.ds.foundations.assets.raw-svg :refer [raw-svg* raw-svg-list]]
[app.main.ui.ds.foundations.typography :refer [typography-list]]
@@ -22,6 +23,7 @@
:Heading heading*
:Icon icon*
:IconButton icon-button*
+ :Input input*
:Loader loader*
:RawSvg raw-svg*
:Text text*
diff --git a/frontend/src/app/main/ui/ds/_borders.scss b/frontend/src/app/main/ui/ds/_borders.scss
index 165ade57d1..a424603d13 100644
--- a/frontend/src/app/main/ui/ds/_borders.scss
+++ b/frontend/src/app/main/ui/ds/_borders.scss
@@ -8,3 +8,5 @@
// TODO: create actual tokens once we have them from design
$br-8: px2rem(8);
+
+$b-1: px2rem(1);
diff --git a/frontend/src/app/main/ui/ds/buttons/_buttons.scss b/frontend/src/app/main/ui/ds/buttons/_buttons.scss
index 7d8c896ac9..b489b4df97 100644
--- a/frontend/src/app/main/ui/ds/buttons/_buttons.scss
+++ b/frontend/src/app/main/ui/ds/buttons/_buttons.scss
@@ -27,7 +27,7 @@
background: var(--button-bg-color);
color: var(--button-fg-color);
- border: 1px solid var(--button-border-color);
+ border: $b-1 solid var(--button-border-color);
&:hover {
--button-bg-color: var(--button-hover-bg-color);
diff --git a/frontend/src/app/main/ui/ds/forms/input.cljs b/frontend/src/app/main/ui/ds/forms/input.cljs
new file mode 100644
index 0000000000..6b97e54493
--- /dev/null
+++ b/frontend/src/app/main/ui/ds/forms/input.cljs
@@ -0,0 +1,32 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+(ns app.main.ui.ds.forms.input
+ (:require-macros
+ [app.common.data.macros :as dm]
+ [app.main.style :as stl])
+ (:require
+ [app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]]
+ [app.util.dom :as dom]
+ [rumext.v2 :as mf]))
+
+(mf/defc input*
+ {::mf/props :obj}
+ [{:keys [icon class type ref] :rest props}]
+ (assert (or (nil? icon) (contains? icon-list icon)))
+ (let [ref (or ref (mf/use-ref))
+ type (or type "text")
+ icon-class (stl/css-case :input true
+ :input-with-icon (some? icon))
+ props (mf/spread-props props {:class icon-class :ref ref :type type})
+ handle-icon-click (mf/use-fn (mf/deps ref)
+ (fn [_]
+ (let [input-node (mf/ref-val ref)]
+ (dom/select-node input-node)
+ (dom/focus! input-node))))]
+ [:> "span" {:class (dm/str class " " (stl/css :container))}
+ (when icon [:> icon* {:id icon :class (stl/css :icon) :on-click handle-icon-click}])
+ [:> "input" props]]))
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/ds/forms/input.mdx b/frontend/src/app/main/ui/ds/forms/input.mdx
new file mode 100644
index 0000000000..2d6d9946a2
--- /dev/null
+++ b/frontend/src/app/main/ui/ds/forms/input.mdx
@@ -0,0 +1,51 @@
+import { Canvas, Meta } from '@storybook/blocks';
+import * as InputStories from "./input.stories";
+
+
+
+# Input
+
+The `input*` component is a wrapper to the HTML `` element with custom styling
+and additional elements that adds context and, in some cases, adds extra
+functionality.
+
+
+
+
+## Technical notes
+
+### Icons
+
+`input*` accepts an `icon` prop, which must contain an [icon ID](../foundations/assets/icon.mdx).
+These are available in the `app.main.ds.foundations.assets.icon` namespace.
+
+```clj
+(ns app.main.ui.foo
+ (:require
+ [app.main.ui.ds.foundations.assets.icon :as i]))
+```
+
+```clj
+[:> input* {:icon i/effects}]
+```
+
+
+
+## Usage guidelines (design)
+
+### Where to use
+
+In forms where the user needs to input any short text or number.
+
+### When to use
+
+When the information that is needed is short and needs an element to add context
+for using it or additional functionality (like color picker).
+
+### Size
+
+The width of the component depends on the content and layout. They can expand to
+fill the container or the content area to which they relate (e.g. tabs) and adapt
+depending on whether there are one or two input elements with or without buttons
+next to them. Their height is always fixed, `32px`, with text area being used for
+larger text blocks.
diff --git a/frontend/src/app/main/ui/ds/forms/input.scss b/frontend/src/app/main/ui/ds/forms/input.scss
new file mode 100644
index 0000000000..027e79878f
--- /dev/null
+++ b/frontend/src/app/main/ui/ds/forms/input.scss
@@ -0,0 +1,64 @@
+@use "../_borders.scss" as *;
+@use "../_sizes.scss" as *;
+@use "../typography.scss" as *;
+
+.container {
+ --input-bg-color: var(--color-background-tertiary);
+ --input-fg-color: var(--color-foreground-primary);
+ --input-icon-color: var(--color-foreground-secondary);
+ --input-outline-color: none;
+
+ display: inline-flex;
+ column-gap: var(--sp-xs);
+ align-items: center;
+ position: relative;
+
+ background: var(--input-bg-color);
+ border-radius: $br-8;
+ padding: 0 var(--sp-s);
+ outline-offset: #{$b-1};
+ outline: $b-1 solid var(--input-outline-color);
+
+ &:hover {
+ --input-bg-color: var(--color-background-quaternary);
+ }
+
+ &:has(*:focus-visible) {
+ --input-bg-color: var(--color-background-primary);
+ --input-outline-color: var(--color-accent-primary);
+ }
+
+ &:has(*:disabled) {
+ --input-bg-color: var(--color-background-primary);
+ --input-outline-color: var(--color-background-quaternary);
+ }
+}
+
+.input {
+ margin: unset; // remove settings from global css
+ padding: 0;
+ appearance: none;
+ margin-inline-start: var(--sp-xxs);
+ height: $sz-32;
+ border: none;
+ background: none;
+
+ @include use-typography("body-small");
+ color: var(--input-fg-color);
+
+ &:focus-visible {
+ outline: none;
+ }
+
+ &::selection {
+ background: var(--color-accent-primary-muted);
+ }
+
+ &::placeholder {
+ --input-fg-color: var(--color-foreground-secondary);
+ }
+}
+
+.icon {
+ color: var(--color-foreground-secondary);
+}
diff --git a/frontend/src/app/main/ui/ds/forms/input.stories.jsx b/frontend/src/app/main/ui/ds/forms/input.stories.jsx
new file mode 100644
index 0000000000..2f01222835
--- /dev/null
+++ b/frontend/src/app/main/ui/ds/forms/input.stories.jsx
@@ -0,0 +1,47 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+//
+// Copyright (c) KALEIDOS INC
+
+import * as React from "react";
+import Components from "@target/components";
+
+const { Input } = Components;
+const { icons } = Components.meta;
+
+export default {
+ title: "Forms/Input",
+ component: Components.Input,
+ argTypes: {
+ icon: {
+ options: icons,
+ control: { type: "select" },
+ },
+ value: {
+ control: { type: "text" },
+ },
+ disabled: { control: "boolean" },
+ },
+ args: {
+ disabled: false,
+ value: "Lorem ipsum",
+ },
+ render: ({ ...args }) => ,
+};
+
+export const Default = {};
+
+export const WithIcon = {
+ args: {
+ icon: "effects",
+ },
+};
+
+export const WithPlaceholder = {
+ args: {
+ icon: "effects",
+ value: undefined,
+ placeholder: "Mixed",
+ },
+};