Files
sigpro-ui/docs/components_old/fieldset.md
2026-04-06 03:19:15 +02:00

21 KiB

Fieldset

Fieldset component for grouping form fields with optional legend and consistent styling.

Tag

Fieldset

Props

Prop Type Default Description
legend string | VNode | Signal - Fieldset legend/title
class string '' Additional CSS classes (DaisyUI + Tailwind)
children VNode | Array<VNode> Required Form fields or content inside the fieldset

Live Examples

Basic Fieldset

Live Demo

const BasicDemo = () => {
  return Fieldset({
    legend: 'User Information',
    class: 'w-full max-w-md mx-auto'
  }, [
    Div({ class: 'space-y-4' }, [
      Input({ label: 'Full Name', placeholder: 'Enter your name' }),
      Input({ label: 'Email', type: 'email', placeholder: 'user@example.com' }),
      Input({ label: 'Phone', type: 'tel', placeholder: '+1 234 567 890' })
    ])
  ]);
};
Mount(BasicDemo, '#demo-basic');

With Reactive Legend

Live Demo

const ReactiveDemo = () => {
  const name = $('');
  const email = $('');
  const isValid = () => name().length > 0 && email().includes('@');
  
  return Fieldset({
    legend: () => isValid() ? '✓ Valid Form' : '✗ Incomplete Form',
    class: 'w-full max-w-md mx-auto'
  }, [
    Div({ class: 'space-y-4' }, [
      Input({ 
        label: 'Full Name', 
        value: name,
        oninput: (e) => name(e.target.value),
        placeholder: 'Enter your name'
      }),
      Input({ 
        label: 'Email', 
        type: 'email',
        value: email,
        oninput: (e) => email(e.target.value),
        placeholder: 'user@example.com'
      }),
      () => isValid() 
        ? Alert({ type: 'success', message: 'Form is ready to submit' })
        : Alert({ type: 'warning', message: 'Please fill all required fields' })
    ])
  ]);
};
Mount(ReactiveDemo, '#demo-reactive');

Address Form

Live Demo

const AddressDemo = () => {
  const address = $('');
  const city = $('');
  const zip = $('');
  const country = $('us');
  
  return Fieldset({
    legend: Span({ class: 'flex items-center gap-2' }, ['📍', 'Shipping Address']),
    class: 'w-full max-w-md mx-auto'
  }, [
    Div({ class: 'space-y-4' }, [
      Input({ label: 'Street Address', value: address, placeholder: '123 Main St', oninput: (e) => address(e.target.value) }),
      Div({ class: 'grid grid-cols-2 gap-4' }, [
        Input({ label: 'City', value: city, placeholder: 'City', oninput: (e) => city(e.target.value) }),
        Input({ label: 'ZIP Code', value: zip, placeholder: 'ZIP', oninput: (e) => zip(e.target.value) })
      ]),
      Select({
        label: 'Country',
        value: country,
        options: [
          { value: 'us', label: 'United States' },
          { value: 'ca', label: 'Canada' },
          { value: 'mx', label: 'Mexico' }
        ],
        onchange: (e) => country(e.target.value)
      })
    ])
  ]);
};
Mount(AddressDemo, '#demo-address');

Payment Method

Live Demo

const PaymentDemo = () => {
  const method = $('credit');
  const cardNumber = $('');
  const expiry = $('');
  const cvv = $('');
  
  return Fieldset({
    legend: Span({ class: 'flex items-center gap-2' }, ['💳', 'Payment Details']),
    class: 'w-full max-w-md mx-auto'
  }, [
    Div({ class: 'space-y-4' }, [
      Div({ class: 'flex gap-4' }, [
        Radio({ label: 'Credit Card', value: method, radioValue: 'credit', onclick: () => method('credit') }),
        Radio({ label: 'PayPal', value: method, radioValue: 'paypal', onclick: () => method('paypal') }),
        Radio({ label: 'Bank Transfer', value: method, radioValue: 'bank', onclick: () => method('bank') })
      ]),
      () => method() === 'credit' ? Div({ class: 'space-y-4' }, [
        Input({ label: 'Card Number', value: cardNumber, placeholder: '1234 5678 9012 3456', oninput: (e) => cardNumber(e.target.value) }),
        Div({ class: 'grid grid-cols-2 gap-4' }, [
          Input({ label: 'Expiry Date', value: expiry, placeholder: 'MM/YY', oninput: (e) => expiry(e.target.value) }),
          Input({ label: 'CVV', type: 'password', value: cvv, placeholder: '123', oninput: (e) => cvv(e.target.value) })
        ])
      ]) : null,
      () => method() === 'paypal' ? Alert({ type: 'info', message: 'You will be redirected to PayPal after confirming.' }) : null,
      () => method() === 'bank' ? Alert({ type: 'warning', message: 'Bank transfer details will be sent via email.' }) : null
    ])
  ]);
};
Mount(PaymentDemo, '#demo-payment');

Preferences Panel

Live Demo

const PreferencesDemo = () => {
  const theme = $('light');
  const language = $('en');
  const notifications = $(true);
  
  return Fieldset({
    legend: Span({ class: 'flex items-center gap-2' }, ['⚙️', 'Preferences']),
    class: 'w-full max-w-md mx-auto'
  }, [
    Div({ class: 'space-y-4' }, [
      Div({ class: 'form-control' }, [
        Span({ class: 'label-text mb-2' }, 'Theme'),
        Div({ class: 'flex gap-4' }, [
          Radio({ label: 'Light', value: theme, radioValue: 'light', onclick: () => theme('light') }),
          Radio({ label: 'Dark', value: theme, radioValue: 'dark', onclick: () => theme('dark') }),
          Radio({ label: 'System', value: theme, radioValue: 'system', onclick: () => theme('system') })
        ])
      ]),
      Select({
        label: 'Language',
        value: language,
        options: [
          { value: 'en', label: 'English' },
          { value: 'es', label: 'Español' },
          { value: 'fr', label: 'Français' }
        ],
        onchange: (e) => language(e.target.value)
      }),
      Checkbox({
        label: 'Enable notifications',
        value: notifications,
        onclick: () => notifications(!notifications())
      })
    ])
  ]);
};
Mount(PreferencesDemo, '#demo-preferences');

Registration Form

Live Demo

const RegistrationDemo = () => {
  const username = $('');
  const email = $('');
  const password = $('');
  const confirmPassword = $('');
  const accepted = $(false);
  
  const passwordsMatch = () => password() === confirmPassword();
  const isFormValid = () => username() && email().includes('@') && password().length >= 6 && passwordsMatch() && accepted();
  
  const handleSubmit = () => {
    if (isFormValid()) {
      Toast('Registration successful!', 'alert-success', 2000);
    }
  };
  
  return Fieldset({
    legend: Span({ class: 'flex items-center gap-2' }, ['📝', 'Create Account']),
    class: 'w-full max-w-md mx-auto'
  }, [
    Div({ class: 'space-y-4' }, [
      Input({ label: 'Username', value: username, placeholder: 'Choose a username', oninput: (e) => username(e.target.value) }),
      Input({ label: 'Email', type: 'email', value: email, placeholder: 'your@email.com', oninput: (e) => email(e.target.value) }),
      Input({ label: 'Password', type: 'password', value: password, placeholder: 'Min. 6 characters', oninput: (e) => password(e.target.value) }),
      Input({ 
        label: 'Confirm Password', 
        type: 'password', 
        value: confirmPassword, 
        error: () => confirmPassword() && !passwordsMatch() ? 'Passwords do not match' : '',
        oninput: (e) => confirmPassword(e.target.value)
      }),
      Checkbox({
        label: 'I accept the Terms and Conditions',
        value: accepted,
        onclick: () => accepted(!accepted())
      }),
      () => !isFormValid() && (username() || email() || password()) ? Alert({ type: 'warning', message: 'Please complete all fields correctly' }) : null,
      Button({ 
        class: 'btn btn-primary w-full', 
        onclick: handleSubmit,
        disabled: () => !isFormValid()
      }, 'Register')
    ])
  ]);
};
Mount(RegistrationDemo, '#demo-registration');

All Variants

Live Demo

const VariantsDemo = () => {
  const commonContent = Div({ class: 'space-y-4' }, [
    Input({ label: 'Field 1', placeholder: 'Enter value' }),
    Input({ label: 'Field 2', placeholder: 'Enter value' }),
    Button({ class: 'btn btn-primary' }, 'Submit')
  ]);
  
  return Div({ class: 'flex flex-col gap-4' }, [
    Fieldset({ legend: 'Default Fieldset', class: 'w-full' }, [commonContent]),
    Fieldset({ legend: 'With Shadow', class: 'w-full shadow-lg' }, [commonContent]),
    Fieldset({ legend: 'With Background', class: 'w-full bg-base-100' }, [commonContent])
  ]);
};
Mount(VariantsDemo, '#demo-variants');
<script> (function() { const initFieldsetExamples = () => { // 1. Basic Fieldset const basicTarget = document.querySelector('#demo-basic'); if (basicTarget && !basicTarget.hasChildNodes()) { const BasicDemo = () => { return Fieldset({ legend: 'User Information', class: 'w-full max-w-md mx-auto' }, [ Div({ class: 'space-y-4' }, [ Input({ label: 'Full Name', placeholder: 'Enter your name' }), Input({ label: 'Email', type: 'email', placeholder: 'user@example.com' }), Input({ label: 'Phone', type: 'tel', placeholder: '+1 234 567 890' }) ]) ]); }; Mount(BasicDemo, basicTarget); } // 2. With Reactive Legend const reactiveTarget = document.querySelector('#demo-reactive'); if (reactiveTarget && !reactiveTarget.hasChildNodes()) { const ReactiveDemo = () => { const name = $(''); const email = $(''); const isValid = () => name().length > 0 && email().includes('@'); return Fieldset({ legend: () => isValid() ? '✓ Valid Form' : '✗ Incomplete Form', class: 'w-full max-w-md mx-auto' }, [ Div({ class: 'space-y-4' }, [ Input({ label: 'Full Name', value: name, oninput: (e) => name(e.target.value), placeholder: 'Enter your name' }), Input({ label: 'Email', type: 'email', value: email, oninput: (e) => email(e.target.value), placeholder: 'user@example.com' }), () => isValid() ? Alert({ type: 'success', message: 'Form is ready to submit' }) : Alert({ type: 'warning', message: 'Please fill all required fields' }) ]) ]); }; Mount(ReactiveDemo, reactiveTarget); } // 3. Address Form const addressTarget = document.querySelector('#demo-address'); if (addressTarget && !addressTarget.hasChildNodes()) { const AddressDemo = () => { const address = $(''); const city = $(''); const zip = $(''); const country = $('us'); return Fieldset({ legend: Span({ class: 'flex items-center gap-2' }, ['📍', 'Shipping Address']), class: 'w-full max-w-md mx-auto' }, [ Div({ class: 'space-y-4' }, [ Input({ label: 'Street Address', value: address, placeholder: '123 Main St', oninput: (e) => address(e.target.value) }), Div({ class: 'grid grid-cols-2 gap-4' }, [ Input({ label: 'City', value: city, placeholder: 'City', oninput: (e) => city(e.target.value) }), Input({ label: 'ZIP Code', value: zip, placeholder: 'ZIP', oninput: (e) => zip(e.target.value) }) ]), Select({ label: 'Country', value: country, options: [ { value: 'us', label: 'United States' }, { value: 'ca', label: 'Canada' }, { value: 'mx', label: 'Mexico' } ], onchange: (e) => country(e.target.value) }) ]) ]); }; Mount(AddressDemo, addressTarget); } // 4. Payment Method const paymentTarget = document.querySelector('#demo-payment'); if (paymentTarget && !paymentTarget.hasChildNodes()) { const PaymentDemo = () => { const method = $('credit'); const cardNumber = $(''); const expiry = $(''); const cvv = $(''); return Fieldset({ legend: Span({ class: 'flex items-center gap-2' }, ['💳', 'Payment Details']), class: 'w-full max-w-md mx-auto' }, [ Div({ class: 'space-y-4' }, [ Div({ class: 'flex gap-4' }, [ Radio({ label: 'Credit Card', value: method, radioValue: 'credit', onclick: () => method('credit') }), Radio({ label: 'PayPal', value: method, radioValue: 'paypal', onclick: () => method('paypal') }), Radio({ label: 'Bank Transfer', value: method, radioValue: 'bank', onclick: () => method('bank') }) ]), () => method() === 'credit' ? Div({ class: 'space-y-4' }, [ Input({ label: 'Card Number', value: cardNumber, placeholder: '1234 5678 9012 3456', oninput: (e) => cardNumber(e.target.value) }), Div({ class: 'grid grid-cols-2 gap-4' }, [ Input({ label: 'Expiry Date', value: expiry, placeholder: 'MM/YY', oninput: (e) => expiry(e.target.value) }), Input({ label: 'CVV', type: 'password', value: cvv, placeholder: '123', oninput: (e) => cvv(e.target.value) }) ]) ]) : null, () => method() === 'paypal' ? Alert({ type: 'info', message: 'You will be redirected to PayPal after confirming.' }) : null, () => method() === 'bank' ? Alert({ type: 'warning', message: 'Bank transfer details will be sent via email.' }) : null ]) ]); }; Mount(PaymentDemo, paymentTarget); } // 5. Preferences Panel const preferencesTarget = document.querySelector('#demo-preferences'); if (preferencesTarget && !preferencesTarget.hasChildNodes()) { const PreferencesDemo = () => { const theme = $('light'); const language = $('en'); const notifications = $(true); return Fieldset({ legend: Span({ class: 'flex items-center gap-2' }, ['⚙️', 'Preferences']), class: 'w-full max-w-md mx-auto' }, [ Div({ class: 'space-y-4' }, [ Div({ class: 'form-control' }, [ Span({ class: 'label-text mb-2' }, 'Theme'), Div({ class: 'flex gap-4' }, [ Radio({ label: 'Light', value: theme, radioValue: 'light', onclick: () => theme('light') }), Radio({ label: 'Dark', value: theme, radioValue: 'dark', onclick: () => theme('dark') }), Radio({ label: 'System', value: theme, radioValue: 'system', onclick: () => theme('system') }) ]) ]), Select({ label: 'Language', value: language, options: [ { value: 'en', label: 'English' }, { value: 'es', label: 'Español' }, { value: 'fr', label: 'Français' } ], onchange: (e) => language(e.target.value) }), Checkbox({ label: 'Enable notifications', value: notifications, onclick: () => notifications(!notifications()) }) ]) ]); }; Mount(PreferencesDemo, preferencesTarget); } // 6. Registration Form const registrationTarget = document.querySelector('#demo-registration'); if (registrationTarget && !registrationTarget.hasChildNodes()) { const RegistrationDemo = () => { const username = $(''); const email = $(''); const password = $(''); const confirmPassword = $(''); const accepted = $(false); const passwordsMatch = () => password() === confirmPassword(); const isFormValid = () => username() && email().includes('@') && password().length >= 6 && passwordsMatch() && accepted(); const handleSubmit = () => { if (isFormValid()) { Toast('Registration successful!', 'alert-success', 2000); } }; return Fieldset({ legend: Span({ class: 'flex items-center gap-2' }, ['📝', 'Create Account']), class: 'w-full max-w-md mx-auto' }, [ Div({ class: 'space-y-4' }, [ Input({ label: 'Username', value: username, placeholder: 'Choose a username', oninput: (e) => username(e.target.value) }), Input({ label: 'Email', type: 'email', value: email, placeholder: 'your@email.com', oninput: (e) => email(e.target.value) }), Input({ label: 'Password', type: 'password', value: password, placeholder: 'Min. 6 characters', oninput: (e) => password(e.target.value) }), Input({ label: 'Confirm Password', type: 'password', value: confirmPassword, error: () => confirmPassword() && !passwordsMatch() ? 'Passwords do not match' : '', oninput: (e) => confirmPassword(e.target.value) }), Checkbox({ label: 'I accept the Terms and Conditions', value: accepted, onclick: () => accepted(!accepted()) }), () => !isFormValid() && (username() || email() || password()) ? Alert({ type: 'warning', message: 'Please complete all fields correctly' }) : null, Button({ class: 'btn btn-primary w-full', onclick: handleSubmit, disabled: () => !isFormValid() }, 'Register') ]) ]); }; Mount(RegistrationDemo, registrationTarget); } // 7. All Variants const variantsTarget = document.querySelector('#demo-variants'); if (variantsTarget && !variantsTarget.hasChildNodes()) { const VariantsDemo = () => { const commonContent = Div({ class: 'space-y-4' }, [ Input({ label: 'Field 1', placeholder: 'Enter value' }), Input({ label: 'Field 2', placeholder: 'Enter value' }), Button({ class: 'btn btn-primary' }, 'Submit') ]); return Div({ class: 'flex flex-col gap-4' }, [ Fieldset({ legend: 'Default Fieldset', class: 'w-full' }, [commonContent]), Fieldset({ legend: 'With Shadow', class: 'w-full shadow-lg' }, [commonContent]), Fieldset({ legend: 'With Background', class: 'w-full bg-base-100' }, [commonContent]) ]); }; Mount(VariantsDemo, variantsTarget); } }; initFieldsetExamples(); if (window.$docsify) { window.$docsify.plugins = [].concat(window.$docsify.plugins || [], (hook) => { hook.doneEach(initFieldsetExamples); }); } })(); </script>