AvesraAvesrabeta

Fieldset

Group related form controls with legends, descriptions, and actions

Import

import { AvFieldsetImports } from '@avesra/angular';

Usage

Apply av-fieldset to a native <fieldset>. Compose av-fieldset-legend, av-fieldset-group, and av-fieldset-actions with shared form primitives like av-label, av-description, and av-field-error.

Profile Settings

Update your profile information.

Minimum 10 characters

import { Component, signal } from '@angular/core';
import {
  AvButtonComponent,
  AvDescriptionComponent,
  AvFieldErrorComponent,
  AvFieldsetImports,
  AvFormComponent,
  AvInputComponent,
  AvLabelComponent,
  AvTextareaComponent,
} from '@avesra/angular';

@Component({
  selector: 'app-fieldset-basic-demo',
  imports: [
    AvFormComponent,
    AvFieldsetImports,
    AvLabelComponent,
    AvDescriptionComponent,
    AvFieldErrorComponent,
    AvInputComponent,
    AvTextareaComponent,
    AvButtonComponent,
  ],
  host: { class: 'w-full max-w-96' },
  template: `<form
      av-form
      class="w-full max-w-96"
      aria-label="Profile settings"
      (submit)="onSubmit($event)"
    >
      <fieldset av-fieldset>
        <legend av-fieldset-legend>Profile Settings</legend>
        <p av-description>Update your profile information.</p>
        <div av-fieldset-group>
          <div class="flex flex-col gap-1">
            <label av-label for="fieldset-name" required>Name</label>
            <input
              av-input
              full-width
              id="fieldset-name"
              name="name"
              placeholder="John Doe"
              required
              minlength="3"
              [invalid]="nameError()"
              (input)="onNameInput($event)"
            />
            <p av-field-error [visible]="nameError()">Name must be at least 3 characters</p>
          </div>
          <div class="flex flex-col gap-1">
            <label av-label for="fieldset-email" required>Email</label>
            <input
              av-input
              full-width
              id="fieldset-email"
              name="email"
              type="email"
              placeholder="john&#64;example.com"
              required
              [invalid]="emailError()"
              (input)="onEmailInput($event)"
            />
            <p av-field-error [visible]="emailError()">Please enter a valid email address</p>
          </div>
          <div class="flex flex-col gap-1">
            <label av-label for="fieldset-bio" required>Bio</label>
            <textarea
              av-textarea
              full-width
              id="fieldset-bio"
              name="bio"
              rows="4"
              placeholder="Tell us about yourself..."
              required
              minlength="10"
              [invalid]="bioError()"
              (input)="onBioInput($event)"
            ></textarea>
            <p av-description>Minimum 10 characters</p>
            <p av-field-error [visible]="bioError()">Bio must be at least 10 characters</p>
          </div>
        </div>
        <div av-fieldset-actions>
          <button av-button type="submit">Save changes</button>
          <button av-button type="reset" variant="secondary">Cancel</button>
        </div>
      </fieldset>
    </form>`,
})
export class FieldsetBasicDemo {
  readonly nameError = signal(false);
  readonly emailError = signal(false);
  readonly bioError = signal(false);

  onNameInput(event: Event): void {
    const value = (event.target as HTMLInputElement).value;
    this.nameError.set(value.length > 0 && value.length < 3);
  }

  onEmailInput(event: Event): void {
    const value = (event.target as HTMLInputElement).value;
    const isValid = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(value);
    this.emailError.set(value.length > 0 && !isValid);
  }

  onBioInput(event: Event): void {
    const value = (event.target as HTMLTextAreaElement).value;
    this.bioError.set(value.length > 0 && value.length < 10);
  }

  onSubmit(event: Event): void {
    event.preventDefault();
    alert('Form submitted successfully!');
  }
}

Anatomy

Import the Fieldset parts and compose them with attribute selectors on native elements.

<fieldset av-fieldset>
  <legend av-fieldset-legend></legend>
  <div av-fieldset-group>
    <!-- form fields go here -->
  </div>
  <div av-fieldset-actions>
    <!-- action buttons go here -->
  </div>
</fieldset>

In Surface

When used inside a Surface component, use variant="secondary" on form controls (Input, Textarea, etc.) to apply the lower emphasis variant suitable for surface backgrounds.

Profile Settings

Update your profile information.

Minimum 10 characters

import { Component, signal } from '@angular/core';
import {
  AvButtonComponent,
  AvDescriptionComponent,
  AvFieldErrorComponent,
  AvFieldsetImports,
  AvFormComponent,
  AvInputComponent,
  AvLabelComponent,
  AvSurfaceComponent,
  AvTextareaComponent,
} from '@avesra/angular';

@Component({
  selector: 'app-fieldset-on-surface-demo',
  imports: [
    AvFormComponent,
    AvFieldsetImports,
    AvLabelComponent,
    AvDescriptionComponent,
    AvFieldErrorComponent,
    AvInputComponent,
    AvTextareaComponent,
    AvButtonComponent,
    AvSurfaceComponent,
  ],
  host: { class: 'flex w-full items-center justify-center' },
  template: `<div class="flex w-full items-center justify-center rounded-3xl bg-surface p-6">
      <div av-surface class="w-full min-w-[380px] max-w-96 p-6">
        <form av-form aria-label="Profile settings" (submit)="onSubmit($event)">
          <fieldset av-fieldset class="w-full">
            <legend av-fieldset-legend>Profile Settings</legend>
            <p av-description>Update your profile information.</p>
            <div av-fieldset-group>
              <div class="flex flex-col gap-1">
                <label av-label for="fieldset-surface-name" required>Name</label>
                <input
                  av-input
                  full-width
                  id="fieldset-surface-name"
                  name="name"
                  placeholder="John Doe"
                  variant="secondary"
                  required
                  minlength="3"
                  [invalid]="nameError()"
                  (input)="onNameInput($event)"
                />
                <p av-field-error [visible]="nameError()">Name must be at least 3 characters</p>
              </div>
              <div class="flex flex-col gap-1">
                <label av-label for="fieldset-surface-email" required>Email</label>
                <input
                  av-input
                  full-width
                  id="fieldset-surface-email"
                  name="email"
                  type="email"
                  placeholder="john&#64;example.com"
                  variant="secondary"
                  required
                  [invalid]="emailError()"
                  (input)="onEmailInput($event)"
                />
                <p av-field-error [visible]="emailError()">Please enter a valid email address</p>
              </div>
              <div class="flex flex-col gap-1">
                <label av-label for="fieldset-surface-bio" required>Bio</label>
                <textarea
                  av-textarea
                  full-width
                  id="fieldset-surface-bio"
                  name="bio"
                  rows="4"
                  placeholder="Tell us about yourself..."
                  variant="secondary"
                  required
                  minlength="10"
                  [invalid]="bioError()"
                  (input)="onBioInput($event)"
                ></textarea>
                <p av-description>Minimum 10 characters</p>
                <p av-field-error [visible]="bioError()">Bio must be at least 10 characters</p>
              </div>
            </div>
            <div av-fieldset-actions>
              <button av-button type="submit">Save changes</button>
              <button av-button type="reset" variant="tertiary">Cancel</button>
            </div>
          </fieldset>
        </form>
      </div>
    </div>`,
})
export class FieldsetOnSurfaceDemo {
  readonly nameError = signal(false);
  readonly emailError = signal(false);
  readonly bioError = signal(false);

  onNameInput(event: Event): void {
    const value = (event.target as HTMLInputElement).value;
    this.nameError.set(value.length > 0 && value.length < 3);
  }

  onEmailInput(event: Event): void {
    const value = (event.target as HTMLInputElement).value;
    const isValid = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(value);
    this.emailError.set(value.length > 0 && !isValid);
  }

  onBioInput(event: Event): void {
    const value = (event.target as HTMLTextAreaElement).value;
    this.bioError.set(value.length > 0 && value.length < 10);
  }

  onSubmit(event: Event): void {
    event.preventDefault();
    alert('Form submitted successfully!');
  }
}

Disabled

Set the disabled attribute on the fieldset to disable descendant form controls. The host also exposes data-disabled="true" for styling.

Profile Settings

This fieldset is disabled.

import { Component } from '@angular/core';
import {
  AvButtonComponent,
  AvDescriptionComponent,
  AvFieldsetImports,
  AvInputComponent,
  AvLabelComponent,
} from '@avesra/angular';

@Component({
  selector: 'app-fieldset-disabled-demo',
  imports: [
    AvFieldsetImports,
    AvLabelComponent,
    AvDescriptionComponent,
    AvInputComponent,
    AvButtonComponent,
  ],
  host: { class: 'w-full max-w-96' },
  template: `<fieldset av-fieldset disabled>
      <legend av-fieldset-legend>Profile Settings</legend>
      <p av-description>This fieldset is disabled.</p>
      <div av-fieldset-group>
        <div class="flex flex-col gap-1">
          <label av-label for="fieldset-disabled-name">Name</label>
          <input av-input full-width id="fieldset-disabled-name" name="name" value="John Doe" />
        </div>
      </div>
      <div av-fieldset-actions>
        <button av-button type="button">Save changes</button>
      </div>
    </fieldset>`,
})
export class FieldsetDisabledDemo {}

Styling

Pass utility classes on host elements, or override BEM classes in @layer components.

CSS Classes

The Fieldset compound component exposes these CSS selectors:

  • .av-fieldset — Root container
  • .av-fieldset__legend — Legend element
  • .av-fieldset__field-group — Wrapper for grouped fields
  • .av-fieldset__actions — Action bar below the fields

API

Fieldset root accepts a disabled input. Legend, group, and actions parts have no Angular inputs — project content via ng-content and style with classes on the host.

PropTypeDefaultDescription
disabledbooleanfalseDisables the fieldset and descendant form controls. Sets data-disabled when true.

Made with ❤ by SyntaxHertz. Open source and available on GitHub.