Skip to content
Merged
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
14 changes: 7 additions & 7 deletions apps/www/src/components/playground/checkbox-examples.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import { Checkbox, Flex, Text } from '@raystack/apsara';
import { Checkbox, Flex, Label, Text } from '@raystack/apsara';
import PlaygroundLayout from './playground-layout';

export function CheckboxExamples() {
Expand All @@ -9,9 +9,9 @@ export function CheckboxExamples() {
<Flex direction='column' gap='large'>
<Flex gap='medium'>
<Checkbox />
<Checkbox checked={true} />
<Checkbox checked='indeterminate' />
<Checkbox checked={true} disabled />
<Checkbox checked />
<Checkbox indeterminate />
<Checkbox checked disabled />
</Flex>
<Text size={2} weight={500}>
Checkbox.Group
Expand All @@ -20,15 +20,15 @@ export function CheckboxExamples() {
<Flex direction='column' gap='small'>
<Flex gap='small' align='center'>
<Checkbox name='apple' id='pg-apple' />
<label htmlFor='pg-apple'>Apple</label>
<Label htmlFor='pg-apple'>Apple</Label>
</Flex>
<Flex gap='small' align='center'>
<Checkbox name='banana' id='pg-banana' />
<label htmlFor='pg-banana'>Banana</label>
<Label htmlFor='pg-banana'>Banana</Label>
</Flex>
<Flex gap='small' align='center'>
<Checkbox name='cherry' id='pg-cherry' />
<label htmlFor='pg-cherry'>Cherry</label>
<Label htmlFor='pg-cherry'>Cherry</Label>
</Flex>
</Flex>
</Checkbox.Group>
Expand Down
23 changes: 12 additions & 11 deletions apps/www/src/components/playground/label-examples.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
'use client';

import { Flex, Label } from '@raystack/apsara';
import { Checkbox, Flex, Label } from '@raystack/apsara';
import PlaygroundLayout from './playground-layout';

export function LabelExamples() {
return (
<PlaygroundLayout title='Label'>
<Flex gap='extra-large' align='center' wrap='wrap'>
<Label size='small'>Small Label</Label>
<Label size='medium'>Medium Label</Label>
<Label size='large'>Large Label</Label>
<Label size='medium' required>
Required Field
</Label>
<Label size='medium' required requiredIndicator=' (Required)'>
Required Field
</Label>
<Flex direction='column' gap='large'>
<Flex direction='column' gap='small'>
<Label htmlFor='pg-label-email'>Email</Label>
<Label htmlFor='pg-label-name' required={false}>
Display name
</Label>
Comment thread
rohanchkrabrty marked this conversation as resolved.
</Flex>
<Flex gap='small' align='center'>
<Checkbox id='pg-label-terms' />
<Label htmlFor='pg-label-terms'>Accept terms</Label>
</Flex>
</Flex>
</PlaygroundLayout>
);
Expand Down
18 changes: 9 additions & 9 deletions apps/www/src/components/playground/radio-examples.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
'use client';

import { Flex, Radio } from '@raystack/apsara';
import { Flex, Label, Radio } from '@raystack/apsara';
import PlaygroundLayout from './playground-layout';

export function RadioExamples() {
return (
<PlaygroundLayout title='Radio'>
<Radio defaultValue='2'>
<Radio.Group defaultValue='2'>
<Flex gap='large'>
<Flex gap='small' align='center'>
<Radio.Item value='1' id='P1' />
<label htmlFor='P1'>Option One</label>
<Radio value='1' id='P1' />
<Label htmlFor='P1'>Option One</Label>
</Flex>
<Flex gap='small' align='center'>
<Radio.Item value='2' id='P2' />
<label htmlFor='P2'>Option Two</label>
<Radio value='2' id='P2' />
<Label htmlFor='P2'>Option Two</Label>
</Flex>
<Flex gap='small' align='center'>
<Radio.Item value='3' id='P3' disabled />
<label htmlFor='P3'>Option Three</label>
<Radio value='3' id='P3' disabled />
<Label htmlFor='P3'>Option Three</Label>
Comment thread
rohanchkrabrty marked this conversation as resolved.
</Flex>
</Flex>
</Radio>
</Radio.Group>
</PlaygroundLayout>
);
}
46 changes: 23 additions & 23 deletions apps/www/src/components/theme-customiser/theme-customiser.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'use client';
import { Button, Radio, Tabs } from '@raystack/apsara';
import { Button, Label, Radio, Tabs } from '@raystack/apsara';
import { getPropsString } from '@/lib/utils';
import { ThemeOptions, useTheme } from '../theme';
import styles from './theme-customiser.module.css';
Expand Down Expand Up @@ -65,7 +65,7 @@ export default function ThemeCustomizer() {
</div>
<div className={styles.section}>
<h3 className={styles.sectionTitle}>Accent Color</h3>
<Radio
<Radio.Group
value={accentColor}
onValueChange={value =>
setTheme({
Expand All @@ -75,55 +75,55 @@ export default function ThemeCustomizer() {
>
<div className={styles.radioGroup}>
<div className={styles.radioOption}>
<Radio.Item value='indigo' id='accent-indigo' />
<label className={styles.radioLabel} htmlFor='accent-indigo'>
<Radio value='indigo' id='accent-indigo' />
<Label className={styles.radioLabel} htmlFor='accent-indigo'>
Indigo
</label>
</Label>
</div>
<div className={styles.radioOption}>
<Radio.Item value='orange' id='accent-orange' />
<label className={styles.radioLabel} htmlFor='accent-orange'>
<Radio value='orange' id='accent-orange' />
<Label className={styles.radioLabel} htmlFor='accent-orange'>
Orange
</label>
</Label>
</div>
<div className={styles.radioOption}>
<Radio.Item value='mint' id='accent-mint' />
<label className={styles.radioLabel} htmlFor='accent-mint'>
<Radio value='mint' id='accent-mint' />
<Label className={styles.radioLabel} htmlFor='accent-mint'>
Mint
</label>
</Label>
</div>
</div>
</Radio>
</Radio.Group>
</div>
<div className={styles.section}>
<h3 className={styles.sectionTitle}>Gray Color</h3>
<Radio
<Radio.Group
value={grayColor}
onValueChange={value =>
setTheme({ grayColor: value as ThemeOptions['grayColor'] })
}
>
<div className={styles.radioGroup}>
<div className={styles.radioOption}>
<Radio.Item value='gray' id='gray-gray' />
<label className={styles.radioLabel} htmlFor='gray-gray'>
<Radio value='gray' id='gray-gray' />
<Label className={styles.radioLabel} htmlFor='gray-gray'>
Gray
</label>
</Label>
</div>
<div className={styles.radioOption}>
<Radio.Item value='mauve' id='gray-mauve' />
<label className={styles.radioLabel} htmlFor='gray-mauve'>
<Radio value='mauve' id='gray-mauve' />
<Label className={styles.radioLabel} htmlFor='gray-mauve'>
Mauve
</label>
</Label>
</div>
<div className={styles.radioOption}>
<Radio.Item value='slate' id='gray-slate' />
<label className={styles.radioLabel} htmlFor='gray-slate'>
<Radio value='slate' id='gray-slate' />
<Label className={styles.radioLabel} htmlFor='gray-slate'>
Slate
</label>
</Label>
</div>
</div>
</Radio>
</Radio.Group>
</div>
<Button onClick={handleCopyTheme} type='button' width='100%'>
Copy Theme Options
Expand Down
33 changes: 14 additions & 19 deletions apps/www/src/content/docs/components/label/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,31 @@ export const getCode = (props: any) => {
export const playground = {
type: 'playground',
controls: {
size: {
type: 'select',
options: ['small', 'medium', 'large'],
defaultValue: 'small'
},
required: { type: 'checkbox', defaultValue: false },
requiredIndicator: { type: 'text', defaultValue: '*' },
required: { type: 'checkbox', defaultValue: true },
optionalText: { type: 'text', defaultValue: '(optional)' },
htmlFor: { type: 'text', defaultValue: '' },
children: { type: 'text', initialValue: 'Label' }
},
getCode
};

export const sizeDemo = {
export const inlineDemo = {
type: 'code',
code: `
<Flex gap="large" align="center">
<Label size="small">Small Label</Label>
<Label size="medium">Medium Label</Label>
<Label size="large">Large Label</Label>
<Flex gap="small" align="center">
<Checkbox id="terms" />
<Label htmlFor="terms">Accept terms</Label>
</Flex>`
};
export const requiredDemo = {

export const optionalDemo = {
type: 'code',
code: `
<Flex gap="large" align="center">
<Label size="medium" required>
Required Field
</Label>
<Label size="medium" required requiredIndicator=" (Required)">
Required Field
<Flex direction="column" gap="small">
<Label>Required field</Label>
<Label required={false}>Optional field</Label>
<Label required={false} optionalText="— not required">
Custom optional text
</Label>
</Flex>`
};
31 changes: 17 additions & 14 deletions apps/www/src/content/docs/components/label/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: A text label component that provides names for form controls.
source: packages/raystack/components/label
---

import { playground, requiredDemo, sizeDemo } from "./demo.ts";
import { inlineDemo, optionalDemo, playground } from "./demo.ts";

<Demo data={playground} />

Expand All @@ -15,35 +15,38 @@ Import and assemble the component:
```tsx
import { Label } from '@raystack/apsara'

<Label />
<Label htmlFor="email">Email</Label>
```

## API Reference

Renders a text label for form elements.
Renders a text label for form elements. Outside of a `Field`, use `Label` to
attach a label to a control via `htmlFor`. Inside a `Field`, prefer
`Field.Label` so the label is wired up to the field automatically.

`Label` is layout-neutral — compose it with `Flex` (or wrap a control as a
child) to lay out the label and its control.

<auto-type-table path="./props.ts" name="LabelProps" />

## Examples

### Size
### Inline with a control

Labels have 3 different sizes.
Use `Flex` to place a label next to a Radio or Checkbox.

<Demo data={sizeDemo} />
<Demo data={inlineDemo} />

### Required
### Optional indicator

Labels can indicate required fields with either a default asterisk or custom text.
Pass `required={false}` to display an `(optional)` indicator next to the label.
Override the text via `optionalText`.

<Demo data={requiredDemo} />
<Demo data={optionalDemo} />

## Accessibility

The Label component is designed with accessibility in mind:

- Uses semantic HTML `<label>` element
- Renders a semantic HTML `<label>` element by default
- Supports programmatic association with form controls via `htmlFor`
- Required indicators are properly hidden from screen readers
- Maintains WCAG compliant color contrast ratios
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Hyphenate “WCAG-compliant” in the accessibility bullet.

Line 51 should use the compound adjective form for correct docs grammar.

Suggested patch
-- Maintains WCAG compliant color contrast ratios
+- Maintains WCAG-compliant color contrast ratios
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- Maintains WCAG compliant color contrast ratios
- Maintains WCAG-compliant color contrast ratios
🧰 Tools
🪛 LanguageTool

[grammar] ~51-~51: Use a hyphen to join words.
Context: ... controls via htmlFor - Maintains WCAG compliant color contrast ratios - Shows ...

(QB_NEW_EN_HYPHEN)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/www/src/content/docs/components/label/index.mdx` at line 51, Replace the
phrase "Maintains WCAG compliant color contrast ratios" with the hyphenated
compound adjective "Maintains WCAG-compliant color contrast ratios" in the Label
component docs (search for that exact text in the index.mdx content for the
Label docs).

- Supports keyboard navigation when used with form controls
- Shows a pointer cursor when associated with a control via `htmlFor`
19 changes: 11 additions & 8 deletions apps/www/src/content/docs/components/label/props.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
export interface LabelProps {
/**
* Controls the size of the label.
* @default "small"
* Whether the labelled control is required. When `false`, an optional
* indicator (see `optionalText`) is rendered next to the label.
*/
size?: 'small' | 'medium' | 'large';

/** When true, shows a required field indicator. */
required?: boolean;

/**
* Customizes the required field indicator.
* @default "*"
* Text rendered next to the label when `required={false}`.
* @defaultValue "(optional)"
*/
requiredIndicator?: string;
optionalText?: string;

/** Associates the label with a form control using its ID. */
htmlFor?: string;

/**
* A React element to override the default rendered element. Allows polymorphic
* rendering while preserving label semantics, classes, and ref forwarding.
*/
render?: React.ReactElement;

/** Additional CSS class names. */
className?: string;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Loading
Loading