@thebase/ui
Version:
CDN-installable Owl and Bootstrap 5 UI component library.
203 lines (180 loc) • 6.45 kB
Markdown
# Form
Build an accessible Bug Report form with BaseUI `Field` layout, BaseUI `Button` actions, and Owl `t-model` input bindings.
## Pure Owl component
```js
import { Component, useState, xml } from "@base/owl";
import {
Button,
Field,
FieldDescription,
FieldGroup,
FieldLabel,
} from "@thebase/ui";
class BugReportExample extends Component {
static components = {
Button,
Field,
FieldDescription,
FieldGroup,
FieldLabel,
};
static template = xml`
<form class="bu-form" data-slot="form" novalidate="novalidate" t-on-submit="submit">
<div class="bu-form-header">
<h3 class="bu-form-title">Bug Report</h3>
<p class="bu-form-description">Help us improve by reporting bugs you encounter.</p>
</div>
<FieldGroup className="'bu-form-fields'">
<Field>
<FieldLabel for="'bug-title'">Bug Title</FieldLabel>
<input
id="bug-title"
name="title"
class="form-control bu-form-control"
type="text"
placeholder="Login button not working on mobile"
autocomplete="off"
t-model="state.title"
/>
</Field>
<Field>
<FieldLabel for="'bug-description'">Description</FieldLabel>
<div class="bu-form-input-group" data-slot="input-group" role="group">
<textarea
id="bug-description"
name="description"
class="form-control bu-form-textarea"
placeholder="I'm having an issue with the login button on mobile."
maxlength="100"
rows="6"
t-model="state.description"
></textarea>
<div class="bu-form-counter" data-slot="input-group-addon" data-align="block-end">
<span class="bu-form-counter-text">
<t t-esc="state.description.length"/>/100 characters
</span>
</div>
</div>
<FieldDescription>Include steps to reproduce, expected behavior, and what actually happened.</FieldDescription>
</Field>
</FieldGroup>
<Field orientation="'horizontal'" className="'bu-form-actions'">
<Button type="'button'" variant="'outline'" onClick="() => this.reset()">Reset</Button>
<Button type="'submit'">Submit</Button>
</Field>
</form>
`;
setup() {
this.state = useState({
title: "",
description: "",
});
}
reset() {
this.state.title = "";
this.state.description = "";
}
submit(event) {
event.preventDefault();
console.log({
title: this.state.title,
description: this.state.description,
});
}
}
```
```base-ui
<form class="bu-form" data-slot="form" novalidate="novalidate" t-on-submit="submit">
<div class="bu-form-header">
<h3 class="bu-form-title">Bug Report</h3>
<p class="bu-form-description">Help us improve by reporting bugs you encounter.</p>
</div>
<FieldGroup className="'bu-form-fields'">
<Field>
<FieldLabel for="'bug-title'">Bug Title</FieldLabel>
<input
id="bug-title"
name="title"
class="form-control bu-form-control"
type="text"
placeholder="Login button not working on mobile"
autocomplete="off"
t-model="state.title"
/>
</Field>
<Field>
<FieldLabel for="'bug-description'">Description</FieldLabel>
<div class="bu-form-input-group" data-slot="input-group" role="group">
<textarea
id="bug-description"
name="description"
class="form-control bu-form-textarea"
placeholder="I'm having an issue with the login button on mobile."
maxlength="100"
rows="6"
t-model="state.description"
></textarea>
<div class="bu-form-counter" data-slot="input-group-addon" data-align="block-end">
<span class="bu-form-counter-text">
<t t-esc="state.description.length"/>/100 characters
</span>
</div>
</div>
<FieldDescription>Include steps to reproduce, expected behavior, and what actually happened.</FieldDescription>
</Field>
</FieldGroup>
<Field orientation="'horizontal'" className="'bu-form-actions'">
<Button type="'button'" variant="'outline'" onClick="() => this.reset()">Reset</Button>
<Button type="'submit'">Submit</Button>
</Field>
</form>
```
This is the same Bug Report form converted from static `b-ui` markup to pure Owl composition: `FieldGroup`, `Field`, `FieldLabel`, `FieldDescription`, and `Button` replace the static adapters, while `t-model` owns the input state.
## State
| Field | Binding | Notes |
| --- | --- | --- |
| `title` | `t-model="state.title"` | trims or validates in your submit handler if needed |
| `description` | `t-model="state.description"` | drives the live `state.description.length` counter |
## Static component
```base-ui
<form b-ui="form">
<div class="bu-form-header">
<h3 class="bu-form-title">Bug Report</h3>
<p class="bu-form-description">Help us improve by reporting bugs you encounter.</p>
</div>
<div b-field-group class="bu-form-fields">
<div b-ui="field">
<label b-field-label for="bug-title">Bug Title</label>
<input
b-ui="input"
id="bug-title"
name="title"
type="text"
placeholder="Login button not working on mobile"
autocomplete="off"
>
</div>
<div b-ui="field">
<label b-field-label for="bug-description">Description</label>
<div class="bu-form-input-group" data-slot="input-group" role="group">
<textarea
b-ui="textarea"
id="bug-description"
name="description"
placeholder="I'm having an issue with the login button on mobile."
maxlength="100"
rows="6"
></textarea>
<div class="bu-form-counter" data-slot="input-group-addon" data-align="block-end">
<span b-form-counter>0/100 characters</span>
</div>
</div>
<p b-field-description>Include steps to reproduce, expected behavior, and what actually happened.</p>
</div>
</div>
<div b-ui="field" b-att-orientation="horizontal" class="bu-form-actions">
<button b-ui="button" b-att-variant="outline" b-form-reset type="button">Reset</button>
<button b-ui="button" type="submit">Submit</button>
</div>
</form>
```