Text input component #30
@ -12,7 +12,8 @@ export interface TextInputProps
|
|||||||
error?: boolean;
|
error?: boolean;
|
||||||
|
stne3960 marked this conversation as resolved
|
|||||||
fullWidth?: boolean;
|
fullWidth?: boolean;
|
||||||
customWidth?: string;
|
customWidth?: string;
|
||||||
label?: string;
|
label: string;
|
||||||
|
hideLabel?: boolean;
|
||||||
message?: string;
|
message?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,6 +71,7 @@ export default function TextInput({
|
|||||||
fullWidth = false,
|
fullWidth = false,
|
||||||
customWidth,
|
customWidth,
|
||||||
label,
|
label,
|
||||||
|
hideLabel = false,
|
||||||
message,
|
message,
|
||||||
className = "",
|
className = "",
|
||||||
...props
|
...props
|
||||||
@ -78,6 +80,7 @@ export default function TextInput({
|
|||||||
const widthStyle = customWidth ? { width: customWidth } : undefined;
|
const widthStyle = customWidth ? { width: customWidth } : undefined;
|
||||||
const stateClasses = error ? errorStateClasses : defaultStateClasses;
|
const stateClasses = error ? errorStateClasses : defaultStateClasses;
|
||||||
const inputPadding = Icon ? "pr-(--padding-md)" : "px-(--padding-md)";
|
const inputPadding = Icon ? "pr-(--padding-md)" : "px-(--padding-md)";
|
||||||
|
const showVisibleLabel = !hideLabel;
|
||||||
|
|
||||||
const inputField = (
|
const inputField = (
|
||||||
<div
|
<div
|
||||||
@ -103,6 +106,7 @@ export default function TextInput({
|
|||||||
)}
|
)}
|
||||||
<input
|
<input
|
||||||
id={inputId}
|
id={inputId}
|
||||||
|
aria-label={hideLabel ? label : undefined}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"flex-1 min-w-0 h-full bg-transparent border-none outline-none",
|
"flex-1 min-w-0 h-full bg-transparent border-none outline-none",
|
||||||
"text-base-ink-max placeholder:text-base-ink-placeholder",
|
"text-base-ink-max placeholder:text-base-ink-placeholder",
|
||||||
@ -114,13 +118,13 @@ export default function TextInput({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!label && !message) {
|
if (!showVisibleLabel && !message) {
|
||||||
return inputField;
|
return inputField;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-(--spacing-sm)">
|
<div className="flex flex-col gap-(--spacing-sm)">
|
||||||
{label && (
|
{showVisibleLabel && (
|
||||||
<label htmlFor={inputId} className="body-bold-md text-base-ink-strong">
|
<label htmlFor={inputId} className="body-bold-md text-base-ink-strong">
|
||||||
{label}
|
{label}
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@ -49,9 +49,9 @@ export default function ComponentLibrary() {
|
|||||||
<section className="mt-lg">
|
<section className="mt-lg">
|
||||||
<h2 className="mb-md">Text Input Sizes</h2>
|
<h2 className="mb-md">Text Input Sizes</h2>
|
||||||
<div className="flex flex-wrap items-center gap-md">
|
<div className="flex flex-wrap items-center gap-md">
|
||||||
<TextInput size="sm" placeholder="Small" />
|
<TextInput size="sm" placeholder="Small" label="Small input" hideLabel />
|
||||||
<TextInput size="md" placeholder="Medium" />
|
<TextInput size="md" placeholder="Medium" label="Medium input" hideLabel />
|
||||||
<TextInput size="lg" placeholder="Large" />
|
<TextInput size="lg" placeholder="Large" label="Large input" hideLabel />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@ -62,16 +62,22 @@ export default function ComponentLibrary() {
|
|||||||
size="sm"
|
size="sm"
|
||||||
placeholder="Small with icon"
|
placeholder="Small with icon"
|
||||||
Icon={SearchIcon}
|
Icon={SearchIcon}
|
||||||
|
label="Small search"
|
||||||
|
hideLabel
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
size="md"
|
size="md"
|
||||||
placeholder="Medium with icon"
|
placeholder="Medium with icon"
|
||||||
Icon={SearchIcon}
|
Icon={SearchIcon}
|
||||||
|
label="Medium search"
|
||||||
|
hideLabel
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
size="lg"
|
size="lg"
|
||||||
placeholder="Large with icon"
|
placeholder="Large with icon"
|
||||||
Icon={SearchIcon}
|
Icon={SearchIcon}
|
||||||
|
label="Large search"
|
||||||
|
hideLabel
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -79,24 +85,24 @@ export default function ComponentLibrary() {
|
|||||||
<section className="mt-lg">
|
<section className="mt-lg">
|
||||||
<h2 className="mb-md">Text Input States</h2>
|
<h2 className="mb-md">Text Input States</h2>
|
||||||
<div className="flex flex-wrap items-center gap-md">
|
<div className="flex flex-wrap items-center gap-md">
|
||||||
<TextInput placeholder="Default" />
|
<TextInput placeholder="Default" label="Default state" hideLabel />
|
||||||
<TextInput placeholder="Error state" error />
|
<TextInput placeholder="Error state" error label="Error state" hideLabel />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="mt-lg">
|
<section className="mt-lg">
|
||||||
<h2 className="mb-md">Text Input With/Without Placeholder</h2>
|
<h2 className="mb-md">Text Input With/Without Placeholder</h2>
|
||||||
<div className="flex flex-wrap items-center gap-md">
|
<div className="flex flex-wrap items-center gap-md">
|
||||||
<TextInput placeholder="Placeholder" />
|
<TextInput placeholder="Placeholder" label="With placeholder" hideLabel />
|
||||||
<TextInput />
|
<TextInput label="Without placeholder" hideLabel />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="mt-lg">
|
<section className="mt-lg">
|
||||||
<h2 className="mb-md">Text Input Width Options</h2>
|
<h2 className="mb-md">Text Input Width Options</h2>
|
||||||
<div className="flex flex-col gap-md">
|
<div className="flex flex-col gap-md">
|
||||||
<TextInput placeholder="Full width" fullWidth />
|
<TextInput placeholder="Full width" fullWidth label="Full width input" hideLabel />
|
||||||
<TextInput placeholder="Custom width" customWidth="300px" />
|
<TextInput placeholder="Custom width" customWidth="300px" label="Custom width input" hideLabel />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user
Without having seen an example of a full form with validation it's hard to tell if this is the path forward. We can probably leave it for now.
I am wondering about using built-in form validation and the
:validand related pseudo-selectors and how it works with accessibility without it.I’d keep the error prop for now. Native validation works for some cases but gets awkward once you have server errors or custom validation. An explicit error state keeps the component predictable.