Profile
Let signed-in users view and edit their profile. Compose your own form field-by-field with <u-profile> + <u-field>, or drop in <u-full-profile> for a complete UI in one tag. Custom attributes, SSO navigation to connected services, and account deletion round it out.
View this guide as MarkdownComposed profile form
u-profile loads and saves the data; each u-field renders one profile field with validation, labels and the right input type (date picker, phone, country select with flags). You own the layout — group fields in any markup you like.
- Field-by-field composition — u-field per profile attribute, your layout
- Typed inputs — dates, phone numbers, country select with icons
- Validation + labels — render-default-label and built-in error handling
<u-signed-in>
<!-- u-profile loads the user's data; each u-field binds one profile field.
partial-validation limits validation to the fields rendered here. -->
<u-profile partial-validation="true">
<u-field field="salutation" render-default-label="true"></u-field>
<div class="grid gap-x-4 sm:grid-cols-2">
<u-field field="first_name" render-default-label="true"></u-field>
<u-field field="last_name" render-default-label="true"></u-field>
<u-field field="date_of_birth" required="true" render-default-label="true"></u-field>
<u-field field="phone_number" render-default-label="true"></u-field>
</div>
<u-field field="country_code" country-code-display-option="icon" render-default-label="true"
></u-field>
<u-submit-button
class-name="mt-4 px-4 py-2 text-white bg-accent hover:bg-accent-hover rounded-lg disabled:opacity-50 w-full cursor-pointer">
Save changes
</u-submit-button>
</u-profile>
</u-signed-in>
<u-signed-in not>
<p class="text-text-light">
Sign in on the <a href="/auth" class="text-primary underline">Auth page</a> to edit your profile.
</p>
</u-signed-in> Full profile in one tag
u-full-profile renders a complete, ready-made profile editor. Use the fields attribute to pick and order fields (including custom_attributes.*), or omit it to show everything the tenant defines. The fastest path to a working account page.
- One component — complete profile UI with zero markup
- Field selection — fields="first_name,last_name,…" picks and orders
<u-signed-in>
<!-- One component, complete profile UI. Limit and order fields with the
fields attribute — or omit it to render everything the tenant defines. -->
<u-full-profile
fields="first_name,last_name,date_of_birth,country_code"
country-code-display-option="icon"></u-full-profile>
</u-signed-in>
<u-signed-in not>
<p class="text-text-light">
Sign in on the <a href="/auth" class="text-primary underline">Auth page</a> to see the full profile
component.
</p>
</u-signed-in> Custom attributes
Tenant-defined custom attributes behave like normal fields via u-field — or use u-raw-field to build fully custom inputs. These sport chips are plain checkboxes bound to a multi-value attribute, styled with CSS only.
- custom_attributes.* fields — text, select, multi-select, radio groups
- u-raw-field escape hatch — any UI you can build with native inputs
<u-signed-in>
<u-profile partial-validation="true">
<u-field field="custom_attributes.fav_athlete" render-default-label="true"></u-field>
<p class="mb-2 mt-4 text-sm font-medium">Favorite disciplines</p>
<div class="discipline-chips-field">
<u-field field="custom_attributes.fav_discipline"></u-field>
</div>
<u-submit-button
class-name="mt-4 px-4 py-2 text-white bg-accent hover:bg-accent-hover rounded-lg disabled:opacity-50 w-full cursor-pointer">
Save changes
</u-submit-button>
</u-profile>
</u-signed-in>
<u-signed-in not>
<p class="text-text-light">
Sign in on the <a href="/auth" class="text-primary underline">Auth page</a> to edit your profile.
</p>
</u-signed-in>
<style is:inline>
.discipline-chips-field u-field::part(multi-select-group_field) {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
padding: 0;
border: none;
background: transparent;
}
.discipline-chips-field u-field::part(multi-select-item_label) {
border-radius: 9999px;
padding: 0 0.875rem;
min-width: 90px;
height: 2.5rem;
justify-content: center;
font-size: 0.875rem;
gap: 0;
background: var(--color-white);
}
.discipline-chips-field u-field::part(multi-select-item_label):hover {
border-color: var(--color-primary);
background: var(--color-primary-soft);
}
.discipline-chips-field u-field::part(multi-select-item_checkbox) {
display: none;
}
.discipline-chips-field u-field::part(multi-select-item_checked) {
background: var(--color-primary-soft);
border-color: var(--color-primary);
color: var(--color-primary-dark);
}
</style> Header profile icon
The classic header pattern: u-signed-in swaps a sign-in link for an avatar menu with profile and logout entries. Pure CSS hover dropdown — no JS required.
- Signed-in/out switch — u-signed-in / u-signed-in not
- u-logout-button anywhere — style it like any menu item
<!-- A header user-menu: avatar button with a hover dropdown.
u-signed-in / u-signed-in not switch between menu and sign-in link. -->
<div class="flex justify-end">
<u-signed-in>
<div class="group relative inline-block">
<button
class="flex items-center justify-center rounded-full border border-border bg-white p-2 shadow-sm hover:bg-background-light"
aria-label="User menu">
<svg class="h-6 w-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="8" r="4"></circle>
<path d="M4 20c0-3.5 3.5-6 8-6s8 2.5 8 6"></path>
</svg>
</button>
<!-- hover bridge so the menu doesn't close between button and panel -->
<div class="absolute left-0 right-0 top-full h-2"></div>
<div
class="absolute right-0 top-full z-20 mt-2 hidden w-48 rounded-lg border border-border bg-white shadow-xl group-hover:block">
<a href="/profile" class="block px-4 py-2 text-sm hover:bg-background-light"
>Profile settings</a
>
<div class="border-t border-border"></div>
<u-logout-button
class-name="block w-full text-left px-4 py-2 text-sm hover:bg-background-light cursor-pointer">
Sign out
</u-logout-button>
</div>
</div>
</u-signed-in>
<u-signed-in not>
<a href="/auth" class="btn btn-primary !min-h-0 !px-4 !py-2 text-sm">Sign in</a>
</u-signed-in>
</div> SSO navigation & account deletion
u-jump-to-service signs the user into another OAuth app of your tenant; u-jump-to-unidy generates a one-time login token and opens Unidy's hosted pages — including the profile page where account deletion lives. no-auth skips the token for public pages.
- Service SSO — jump into connected apps without re-login
- Hosted Unidy pages — subscriptions, tickets, terms, profile
- Account deletion — deep-link to /profile#logindata
<u-signed-in>
<div class="flex flex-col gap-3">
<!-- SSO jump to the FIS Fan Portal (service-id = 6) -->
<u-jump-to-service
service-id="6"
newtab
class-name="px-4 py-2 bg-accent hover:bg-accent-hover text-white text-sm font-medium rounded-lg cursor-pointer disabled:opacity-50">
Open FIS Fan Portal
</u-jump-to-service>
<!-- One-time-token jump into Unidy's hosted pages -->
<u-jump-to-unidy
path="/subscriptions"
newtab
class-name="px-4 py-2 border border-border text-sm font-medium rounded-lg cursor-pointer hover:bg-background-light disabled:opacity-50">
Manage subscriptions in Unidy
</u-jump-to-unidy>
<!-- Pages that need no authentication: add no-auth -->
<u-jump-to-unidy
path="/terms_of_use"
no-auth
newtab
class-name="text-sm text-text-light underline cursor-pointer hover:text-text">
Terms of use (no auth)
</u-jump-to-unidy>
<!-- Account deletion lives on Unidy's profile page — deep-link straight to it -->
<u-jump-to-unidy
path="/profile#logindata"
newtab
class-name="px-4 py-2 bg-danger hover:bg-danger-hover text-white text-sm font-medium rounded-lg cursor-pointer disabled:opacity-50">
Delete my account
</u-jump-to-unidy>
</div>
</u-signed-in>
<u-signed-in not>
<p class="text-text-light">
Sign in on the <a href="/auth" class="text-primary underline">Auth page</a> to use SSO navigation.
</p>
</u-signed-in> Sign in on the Auth page to use SSO navigation.