diff --git a/.changeset/sharp-maps-leave.md b/.changeset/sharp-maps-leave.md
new file mode 100644
index 000000000..62d05264d
--- /dev/null
+++ b/.changeset/sharp-maps-leave.md
@@ -0,0 +1,5 @@
+---
+"@khanacademy/wonder-blocks-form": patch
+---
+
+Improve `LabeledTextField` styling when the `light` prop is `true`. This improves the color contrast of the label, required indicator, description, and error message when the component is used on dark backgrounds.
diff --git a/__docs__/wonder-blocks-form/labeled-text-field.stories.tsx b/__docs__/wonder-blocks-form/labeled-text-field.stories.tsx
index 3212d2a24..f2830e4a9 100644
--- a/__docs__/wonder-blocks-form/labeled-text-field.stories.tsx
+++ b/__docs__/wonder-blocks-form/labeled-text-field.stories.tsx
@@ -3,8 +3,7 @@ import {StyleSheet} from "aphrodite";
import type {Meta, StoryObj} from "@storybook/react";
import {View} from "@khanacademy/wonder-blocks-core";
-import {LabelMedium, LabelSmall} from "@khanacademy/wonder-blocks-typography";
-import {color, spacing} from "@khanacademy/wonder-blocks-tokens";
+import {spacing} from "@khanacademy/wonder-blocks-tokens";
import {Strut} from "@khanacademy/wonder-blocks-layout";
import Button from "@khanacademy/wonder-blocks-button";
import Link from "@khanacademy/wonder-blocks-link";
@@ -436,6 +435,15 @@ export const Error: StoryComponentType = {
render: ErrorRender,
};
+/**
+ * The `light` prop is intended to be used on a dark background. When the
+ * `light` prop is set to `true`:
+ * - the underlying `TextField` will have a light border when focused
+ * - a specific light styling is used for the error state, as seen in the
+ * `ErrorLight` story
+ * - the text in the component (label, required indicator, description, and
+ * error message) are modified to work on the dark background
+ */
export const Light: StoryComponentType = (args: any) => {
const [value, setValue] = React.useState("");
@@ -446,24 +454,17 @@ export const Light: StoryComponentType = (args: any) => {
};
return (
-
- Name
- }
- description={
-
- Please enter your name
-
- }
- value={value}
- onChange={setValue}
- placeholder="Name"
- light={true}
- onKeyDown={handleKeyDown}
- />
-
+
);
};
@@ -472,17 +473,15 @@ Light.args = {
};
Light.parameters = {
- docs: {
- description: {
- story: `If the \`light\` prop is set to true, the
- underlying \`TextField\` will have a light border when focused.
- This is intended to be used on a dark background. There is also a
- specific light styling for the error state, as seen in the
- \`ErrorLight\` story.`,
- },
+ backgrounds: {
+ default: "darkBlue",
},
};
+/**
+ * If an input value fails validation and the `light` prop is true,
+ * `TextField` will have light error styling.
+ */
export const ErrorLight: StoryComponentType = (args: any) => {
const [value, setValue] = React.useState("khan");
@@ -500,26 +499,19 @@ export const ErrorLight: StoryComponentType = (args: any) => {
};
return (
-
- Email
- }
- description={
-
- Please provide your personal email
-
- }
- type="email"
- value={value}
- light={true}
- onChange={setValue}
- placeholder="Email"
- validate={validate}
- onKeyDown={handleKeyDown}
- />
-
+
);
};
@@ -528,11 +520,8 @@ ErrorLight.args = {
};
ErrorLight.parameters = {
- docs: {
- description: {
- story: `If an input value fails validation and the
- \`light\` prop is true, \`TextField\` will have light error styling.`,
- },
+ backgrounds: {
+ default: "darkBlue",
},
};
@@ -766,16 +755,6 @@ AutoComplete.parameters = {
};
const styles = StyleSheet.create({
- darkBackground: {
- background: color.darkBlue,
- padding: `${spacing.medium_16}px`,
- },
- whiteColor: {
- color: color.white,
- },
- offWhiteColor: {
- color: color.white64,
- },
button: {
maxWidth: 150,
},
diff --git a/packages/wonder-blocks-form/src/components/field-heading.tsx b/packages/wonder-blocks-form/src/components/field-heading.tsx
index 56553b929..b8198fe49 100644
--- a/packages/wonder-blocks-form/src/components/field-heading.tsx
+++ b/packages/wonder-blocks-form/src/components/field-heading.tsx
@@ -42,6 +42,10 @@ type Props = {
* Optional test ID for e2e testing.
*/
testId?: string;
+ /**
+ * Change the field’s sub-components to fit a dark background.
+ */
+ light?: boolean;
};
const StyledSpan = addStyle("span");
@@ -52,10 +56,13 @@ const StyledSpan = addStyle("span");
*/
export default class FieldHeading extends React.Component {
renderLabel(): React.ReactNode {
- const {label, id, required, testId} = this.props;
+ const {label, id, required, testId, light} = this.props;
const requiredIcon = (
-
+
{" "}
*
@@ -64,7 +71,7 @@ export default class FieldHeading extends React.Component {
return (
{
}
maybeRenderDescription(): React.ReactNode | null | undefined {
- const {description, testId} = this.props;
+ const {description, testId, light} = this.props;
if (!description) {
return null;
@@ -87,7 +94,7 @@ export default class FieldHeading extends React.Component {
return (
{description}
@@ -98,7 +105,7 @@ export default class FieldHeading extends React.Component {
}
maybeRenderError(): React.ReactNode | null | undefined {
- const {error, id, testId} = this.props;
+ const {error, id, testId, light} = this.props;
if (!error) {
return null;
@@ -108,7 +115,7 @@ export default class FieldHeading extends React.Component {
{
id={uniqueId}
testId={testId}
style={style}
+ light={light}
field={