diff --git a/packages/grafana-ui/src/components/Forms/TextArea/TextArea.mdx b/packages/grafana-ui/src/components/Forms/TextArea/TextArea.mdx
new file mode 100644
index 00000000000..e31487cacd0
--- /dev/null
+++ b/packages/grafana-ui/src/components/Forms/TextArea/TextArea.mdx
@@ -0,0 +1,7 @@
+import { Props } from '@storybook/addon-docs/blocks';
+import { TextArea } from './TextArea';
+
+# TextArea
+Use for multi line inputs like descriptions.
+
+
diff --git a/packages/grafana-ui/src/components/Forms/TextArea/TextArea.story.tsx b/packages/grafana-ui/src/components/Forms/TextArea/TextArea.story.tsx
new file mode 100644
index 00000000000..f58c6bfbc0a
--- /dev/null
+++ b/packages/grafana-ui/src/components/Forms/TextArea/TextArea.story.tsx
@@ -0,0 +1,49 @@
+import React from 'react';
+import { TextArea } from './TextArea';
+import { withCenteredStory } from '../../../utils/storybook/withCenteredStory';
+import { boolean, number, select, text } from '@storybook/addon-knobs';
+import mdx from './TextArea.mdx';
+
+export default {
+ title: 'UI/Forms/TextArea',
+ component: TextArea,
+ decorators: [withCenteredStory],
+ parameters: {
+ docs: {
+ page: mdx,
+ },
+ },
+};
+
+export const simple = () => {
+ const BEHAVIOUR_GROUP = 'Behaviour props';
+ // ---
+ const invalid = boolean('Invalid', false, BEHAVIOUR_GROUP);
+ const disabled = boolean('Disabled', false, BEHAVIOUR_GROUP);
+
+ const VISUAL_GROUP = 'Visual options';
+ // ---
+ const placeholder = text('Placeholder', 'This is just a placeholder', VISUAL_GROUP);
+ const cols = number('Cols', 30, { range: true, min: 5, max: 50, step: 5 }, VISUAL_GROUP);
+ const size = select('Size', ['sm', 'md', 'lg', 'auto'], undefined, VISUAL_GROUP);
+
+ const CONTAINER_GROUP = 'Container options';
+ // ---
+ const containerWidth = number(
+ 'Container width',
+ 300,
+ {
+ range: true,
+ min: 100,
+ max: 500,
+ step: 10,
+ },
+ CONTAINER_GROUP
+ );
+
+ return (
+
+
+
+ );
+};
diff --git a/packages/grafana-ui/src/components/Forms/TextArea/TextArea.tsx b/packages/grafana-ui/src/components/Forms/TextArea/TextArea.tsx
new file mode 100644
index 00000000000..54311eee7e6
--- /dev/null
+++ b/packages/grafana-ui/src/components/Forms/TextArea/TextArea.tsx
@@ -0,0 +1,38 @@
+import React, { FC, HTMLProps } from 'react';
+import { GrafanaTheme } from '@grafana/data';
+import { css, cx } from 'emotion';
+import { stylesFactory, useTheme } from '../../../themes';
+import { getFocusStyle, inputSizes, sharedInputStyle } from '../commonStyles';
+import { FormInputSize } from '../types';
+
+export interface Props extends Omit
, 'size'> {
+ /** Show an invalid state around the input */
+ invalid?: boolean;
+ /** Choose a predefined size */
+ size?: FormInputSize;
+}
+
+const getTextAreaStyle = stylesFactory((theme: GrafanaTheme, invalid = false) => {
+ return {
+ textarea: cx(
+ sharedInputStyle(theme),
+ getFocusStyle(theme),
+ css`
+ border-radius: ${theme.border.radius.sm};
+ padding: ${theme.spacing.formSpacingBase / 4}px ${theme.spacing.formSpacingBase}px;
+ width: 100%;
+ `
+ ),
+ };
+});
+
+export const TextArea: FC = ({ invalid, size = 'auto', ...props }) => {
+ const theme = useTheme();
+ const styles = getTextAreaStyle(theme, invalid);
+
+ return (
+
+
+
+ );
+};
diff --git a/packages/grafana-ui/src/components/Forms/commonStyles.ts b/packages/grafana-ui/src/components/Forms/commonStyles.ts
index ad2408c0504..5720c312957 100644
--- a/packages/grafana-ui/src/components/Forms/commonStyles.ts
+++ b/packages/grafana-ui/src/components/Forms/commonStyles.ts
@@ -9,3 +9,46 @@ export const getFocusStyle = (theme: GrafanaTheme) => css`
transition: all 0.2s cubic-bezier(0.19, 1, 0.22, 1);
}
`;
+
+export const sharedInputStyle = (theme: GrafanaTheme, invalid = false) => {
+ const colors = theme.colors;
+ const borderColor = invalid ? colors.redBase : colors.formInputBorder;
+
+ return css`
+ background-color: ${colors.formInputBg};
+ line-height: ${theme.typography.lineHeight.lg};
+ font-size: ${theme.typography.size.md};
+ color: ${colors.formInputText};
+ border: 1px solid ${borderColor};
+
+ &:hover {
+ border-color: ${colors.formInputBorder};
+ }
+
+ &:focus {
+ outline: none;
+ }
+
+ &:disabled {
+ background-color: ${colors.formInputBgDisabled};
+ color: ${colors.formInputDisabledText};
+ }
+ `;
+};
+
+export const inputSizes = () => {
+ return {
+ sm: css`
+ width: 200px;
+ `,
+ md: css`
+ width: 320px;
+ `,
+ lg: css`
+ width: 580px;
+ `,
+ auto: css`
+ width: 100%;
+ `,
+ };
+};
diff --git a/packages/grafana-ui/src/components/Forms/types.ts b/packages/grafana-ui/src/components/Forms/types.ts
new file mode 100644
index 00000000000..6e45eed34ab
--- /dev/null
+++ b/packages/grafana-ui/src/components/Forms/types.ts
@@ -0,0 +1 @@
+export type FormInputSize = 'sm' | 'md' | 'lg' | 'auto';