Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/textarea-auto-size.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': minor
---

Textarea: Add an `autoSize` option that allows the field to grow with its content
4 changes: 4 additions & 0 deletions packages/react/src/Textarea/TextArea.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
resize: vertical;
}

.TextArea[data-auto-size='true'] {
field-sizing: content;
}

.TextArea:disabled {
resize: none;
}
Expand Down
8 changes: 7 additions & 1 deletion packages/react/src/Textarea/Textarea.docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@
"defaultValue": "'both'",
"description": "Changes the resize behavior"
},
{
"name": "autoSize",
"type": "boolean",
"defaultValue": "false",
"description": "Allows the textarea to grow to fit its content"
},
{
"name": "characterLimit",
"type": "number",
Expand Down Expand Up @@ -110,4 +116,4 @@
}
],
"subcomponents": []
}
}
9 changes: 9 additions & 0 deletions packages/react/src/Textarea/Textarea.features.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ export const CustomResizeBehavior = () => (
</Stack>
)

export const AutoSize = () => (
<form>
<FormControl>
<FormControl.Label>Automatically growing textarea</FormControl.Label>
<Textarea autoSize />
</FormControl>
</form>
)

export const MinimumHeight = () => (
<form>
<FormControl>
Expand Down
4 changes: 4 additions & 0 deletions packages/react/src/Textarea/Textarea.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Playground.args = {
block: false,
cols: DEFAULT_TEXTAREA_COLS,
disabled: false,
autoSize: false,
resize: DEFAULT_TEXTAREA_RESIZE,
contrast: false,
rows: DEFAULT_TEXTAREA_ROWS,
Expand All @@ -45,6 +46,9 @@ Playground.argTypes = {
disabled: {
control: {type: 'boolean'},
},
autoSize: {
control: {type: 'boolean'},
},
resize: {
options: ['none', 'both', 'horizontal', 'vertical'],
control: {type: 'radio'},
Expand Down
11 changes: 11 additions & 0 deletions packages/react/src/Textarea/Textarea.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ describe('Textarea', () => {
expect(hasResizeDeclaration).toBe(true)
})

it('enables automatic sizing without changing resize behavior', () => {
render(<Textarea autoSize resize="vertical" />)
const textareaElement = screen.getByRole('textbox')

expect(textareaElement).toHaveAttribute('data-auto-size', 'true')
expect(textareaElement).toHaveAttribute('data-resize', 'vertical')

const rules = getCSSRules(`.${classes.TextArea}[data-auto-size="true"]`)
expect(rules.some(rule => rule.style.getPropertyValue('field-sizing') === 'content')).toBe(true)
})

it('renders a value in the textarea', () => {
const mockValue = 'mock value'
const onChange = vi.fn()
Expand Down
6 changes: 6 additions & 0 deletions packages/react/src/Textarea/Textarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ export type TextareaProps = {
* Allows resizing of the textarea
*/
resize?: 'none' | 'both' | 'horizontal' | 'vertical'
/**
* Allows the textarea to grow to fit its content
*/
autoSize?: boolean
/**
* apply a high contrast color to background
*/
Expand Down Expand Up @@ -74,6 +78,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
rows = DEFAULT_TEXTAREA_ROWS,
cols = DEFAULT_TEXTAREA_COLS,
resize = DEFAULT_TEXTAREA_RESIZE,
autoSize,
block,
contrast,
className,
Expand Down Expand Up @@ -133,6 +138,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
defaultValue={defaultValue}
data-component="Textarea"
data-resize={resize}
data-auto-size={autoSize || undefined}
aria-required={required}
aria-invalid={isValid === 'error' ? 'true' : 'false'}
ref={ref}
Expand Down
Loading