<fieldset class="field-group m-form-control m-form-control--large m-radiobutton-advanced js-radiobutton-advanced">
<legend class="label-legend" id="radiobutton-advanced-legend">Vad vill du söka efter?</legend>
<p class="u-visuallyhidden" id="radiobutton-advanced-help">På mindre skärmar visas bara valt alternativ. Aktivera det synliga alternativet för att visa alla alternativ. Tryck Enter eller Escape för att stänga listan.</p>
<p class="u-visuallyhidden js-radiobutton-advanced__status" id="radiobutton-advanced-status" aria-live="polite" aria-atomic="true"></p>
<div class="m-radiobutton-advanced__options js-radiobutton-advanced__options" id="radiobutton-advanced-options" aria-labelledby="radiobutton-advanced-legend" aria-describedby="radiobutton-advanced-help radiobutton-advanced-status" aria-expanded="false">
<div class="radio m-radiobutton-advanced__option js-radiobutton-advanced__option">
<input type="radio" id="radiobutton-advanced-1" name="radiobutton-advanced" value="first" class="a-radio u-visuallyhidden js-radiobutton-advanced__input" data-placeholder="t.ex. volvo.se" aria-describedby="radiobutton-advanced-1-description">
<label for="radiobutton-advanced-1">
<span class="m-radiobutton-advanced__content">
<span class="m-radiobutton-advanced__label">Domän</span>
<span class="m-radiobutton-advanced__description" id="radiobutton-advanced-1-description">Sök efter .se eller .nu-domän.</span>
</span>
<span class="m-radiobutton-advanced__icon" aria-hidden="true">
<span></span>
<span></span>
<span></span>
</span>
</label>
</div>
<div class="radio m-radiobutton-advanced__option js-radiobutton-advanced__option">
<input type="radio" id="radiobutton-advanced-2" name="radiobutton-advanced" value="second" class="a-radio u-visuallyhidden js-radiobutton-advanced__input" data-placeholder="t.ex. volvo" aria-describedby="radiobutton-advanced-2-description">
<label for="radiobutton-advanced-2">
<span class="m-radiobutton-advanced__content">
<span class="m-radiobutton-advanced__label">Nyckelord</span>
<span class="m-radiobutton-advanced__description" id="radiobutton-advanced-2-description">Sök efter alla domäner med detta nyckelord.</span>
</span>
<span class="m-radiobutton-advanced__icon" aria-hidden="true">
<span></span>
<span></span>
<span></span>
</span>
</label>
</div>
<div class="radio m-radiobutton-advanced__option js-radiobutton-advanced__option">
<input type="radio" id="radiobutton-advanced-3" name="radiobutton-advanced" value="third" class="a-radio u-visuallyhidden js-radiobutton-advanced__input" data-placeholder="t.ex. 556810-8988" aria-describedby="radiobutton-advanced-3-description">
<label for="radiobutton-advanced-3">
<span class="m-radiobutton-advanced__content">
<span class="m-radiobutton-advanced__label">Organisationsnummer</span>
<span class="m-radiobutton-advanced__description" id="radiobutton-advanced-3-description">Sök alla domäner registrerade med detta organisationsnummer.</span>
</span>
<span class="m-radiobutton-advanced__icon" aria-hidden="true">
<span></span>
<span></span>
<span></span>
</span>
</label>
</div>
</div>
</fieldset>
<fieldset class="field-group m-form-control m-form-control--large m-radiobutton-advanced js-radiobutton-advanced{{#if is_invalid}} is-invalid{{/if}}">
<legend class="label-legend" id="{{name}}-legend">{{legend}}</legend>
<p class="u-visuallyhidden" id="{{name}}-help">På mindre skärmar visas bara valt alternativ. Aktivera det synliga alternativet för att visa alla alternativ. Tryck Enter eller Escape för att stänga listan.</p>
<p class="u-visuallyhidden js-radiobutton-advanced__status" id="{{name}}-status" aria-live="polite" aria-atomic="true"></p>
<div class="m-radiobutton-advanced__options js-radiobutton-advanced__options" id="{{name}}-options" aria-labelledby="{{name}}-legend" aria-describedby="{{name}}-help {{name}}-status" aria-expanded="false">
{{#each options}}
<div class="radio m-radiobutton-advanced__option js-radiobutton-advanced__option{{#if ../is_invalid}} is-invalid{{/if}}">
<input type="radio" id="{{id}}" name="{{../name}}" value="{{value}}" class="a-radio u-visuallyhidden js-radiobutton-advanced__input"{{#if placeholder}} data-placeholder="{{placeholder}}"{{/if}}{{#if description}} aria-describedby="{{id}}-description"{{/if}}{{#if is_checked}} checked{{/if}}{{#ifequals value ../selected_value}} checked{{/ifequals}}{{#if ../is_disabled}} disabled{{else}}{{#if is_disabled}} disabled{{/if}}{{/if}}{{#if ../is_required}} required{{else}}{{#if is_required}} required{{/if}}{{/if}}{{#if ../is_invalid}} aria-invalid="true"{{else}}{{#if is_invalid}} aria-invalid="true"{{/if}}{{/if}}>
<label for="{{id}}">
<span class="m-radiobutton-advanced__content">
<span class="m-radiobutton-advanced__label">{{label}}</span>
{{#if description}}<span class="m-radiobutton-advanced__description" id="{{id}}-description">{{description}}</span>{{/if}}
</span>
<span class="m-radiobutton-advanced__icon" aria-hidden="true">
<span></span>
<span></span>
<span></span>
</span>
</label>
</div>
{{/each}}
</div>
</fieldset>
{
"legend": "Vad vill du söka efter?",
"name": "radiobutton-advanced",
"options": [
{
"id": "radiobutton-advanced-1",
"label": "Domän",
"description": "Sök efter .se eller .nu-domän.",
"value": "first",
"placeholder": "t.ex. volvo.se"
},
{
"id": "radiobutton-advanced-2",
"label": "Nyckelord",
"description": "Sök efter alla domäner med detta nyckelord.",
"value": "second",
"placeholder": "t.ex. volvo"
},
{
"id": "radiobutton-advanced-3",
"label": "Organisationsnummer",
"description": "Sök alla domäner registrerade med detta organisationsnummer.",
"value": "third",
"placeholder": "t.ex. 556810-8988"
}
]
}
@charset "UTF-8";
@use '../../configurations/mixins' as mixin;
@use '../../configurations/bem' as bem;
@use '../../configurations/variables' as var;
@use '../../configurations/functions' as func;
@use '../../configurations/colors/colors' as colors;
@use '../../vendor/grid/breakpoints' as breakpoint;
@keyframes radiobutton-advanced-icon-pulse {
0% {
transform: scale(1);
opacity: 0.8;
}
45% {
transform: scale(1.65);
opacity: 0;
}
100% {
transform: scale(1.65);
opacity: 0;
}
}
@include mixin.molecule(radiobutton-advanced) {
@include breakpoint.bp-down(sm) {
&.is-expanded {
padding-bottom: var(--radiobutton-advanced-collapsed-height, 0);
[class*='m-radiobutton-advanced__options'] {
position: absolute;
right: 0;
left: 0;
z-index: func.z_index(foreground);
padding: func.rhythm(1);
border: 1px solid colors.$color-concrete;
border-radius: var.$border-radius;
background-color: colors.$color-snow;
}
}
&.is-collapsed:not(.is-expanded) {
[class*='m-radiobutton-advanced__options'] > [class*='m-radiobutton-advanced__option'] {
@include mixin.visuallyhidden;
&.is-visible {
position: static;
width: auto;
height: auto;
margin-bottom: 0;
overflow: visible;
clip: auto;
}
}
[class*='m-radiobutton-advanced__options'] > [class*='m-radiobutton-advanced__option'].is-visible {
cursor: pointer;
[class*='m-radiobutton-advanced__icon'] {
display: inline-flex;
}
}
}
&.is-collapsed:not(.is-expanded):not(.has-selection) {
[class*='m-radiobutton-advanced__options'] > [class*='m-radiobutton-advanced__option'].is-visible {
[class*='m-radiobutton-advanced__icon'] {
background-color: colors.$color-ocean-lighter;
&::after {
animation: radiobutton-advanced-icon-pulse 2.8s ease-out infinite;
}
}
}
}
}
@include bem.e(options) {
width: 100%;
@include breakpoint.bp-up(md) {
display: flex;
flex-wrap: wrap;
gap: func.rhythm(1);
}
}
@include bem.e(option) {
margin-bottom: func.rhythm(1);
border: 1px solid colors.$color-concrete;
border-radius: var.$border-radius;
background-color: colors.$color-snow;
box-shadow: none;
transition: box-shadow 0.25s ease;
&:last-child {
margin-bottom: 0;
}
@include breakpoint.bp-up(md) {
flex: 1 1 0;
margin-bottom: 0;
}
&.is-checked {
border-color: colors.$color-ocean-light;
background-color: colors.$color-ocean-lighter;
box-shadow: 0 0 0 2px colors.$color-ocean-light, 0 func.rhythm(0.5) func.rhythm(0.5) rgba(colors.$color-cyberspace, 0.1);
> label {
&:hover,
&:focus {
background-color: colors.$color-ocean-lighter;
}
}
}
> label {
width: 100%;
height: 100%;
padding-left: func.rhythm(1);
padding-right: func.rhythm(1);
margin-bottom: 0;
&:hover,
&:focus {
background-color: colors.$color-ash;
}
@include breakpoint.bp-up(md) {
padding-left: func.rhythm(1.5);
padding-right: func.rhythm(1.5);
padding-top: func.rhythm(1) !important;
padding-bottom: func.rhythm(1) !important;
}
}
}
@include bem.e(content) {
display: block;
flex-grow: 1;
}
@include bem.e(label) {
display: block;
font-family: var.$font-family-medium;
}
@include bem.e(description) {
display: block;
margin-top: func.rhythm(0.25);
color: colors.$color-dark;
font-size: var.$size-medium;
line-height: 1.4;
}
@include bem.e(icon) {
display: none;
position: relative;
flex-direction: column;
justify-content: center;
align-items: center;
flex-shrink: 0;
gap: func.to_rem(3px);
align-self: center;
margin-left: func.rhythm(1);
padding: func.rhythm(0.5);
width: func.to_rem(28px);
height: func.to_rem(28px);
border-radius: 50%;
background-color: colors.$color-snow;
&::after {
position: absolute;
inset: 0;
border-radius: 50%;
box-shadow: 0 0 0 2px colors.$color-ocean;
content: '';
opacity: 0;
pointer-events: none;
}
> span {
width: func.to_rem(4px);
height: func.to_rem(4px);
border-radius: 50%;
background-color: colors.$color-cyberspace;
}
}
}
import className from '../../assets/js/className';
const radiobuttonAdvancedGroups = document.querySelectorAll('.js-radiobutton-advanced');
const optionsSelector = '.js-radiobutton-advanced__options';
const optionSelector = '.js-radiobutton-advanced__option';
const inputSelector = '.js-radiobutton-advanced__input';
const statusSelector = '.js-radiobutton-advanced__status';
const labelSelector = `.${className('m-radiobutton-advanced__label')}`;
const collapsedLayout = window.matchMedia('(max-width: 768px)');
const keyboardInteractionGroups = new WeakSet();
const keyboardExpandKeys = ['Enter', ' ', 'Spacebar'];
const keyboardSelectionKeys = ['ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'End', 'Home', ' ', 'Spacebar'];
function getOptions(group) {
return Array.from(group.querySelectorAll(optionSelector));
}
function getInput(option) {
return option.querySelector(inputSelector);
}
function getVisibleOption(options) {
return options.find((option) => {
const input = getInput(option);
return input && input.checked;
}) || options[0];
}
function getOptionLabel(option) {
const label = option.querySelector(labelSelector);
return label ? label.textContent.trim() : '';
}
function setCheckedState(group) {
const options = getOptions(group);
let hasCheckedOption = false;
options.forEach((option) => {
const input = getInput(option);
if (!input) {
return;
}
option.classList.toggle('is-checked', input.checked);
hasCheckedOption = hasCheckedOption || input.checked;
});
group.classList.toggle('has-selection', hasCheckedOption);
}
function setVisibleState(group) {
const options = getOptions(group);
const visibleOption = getVisibleOption(options);
options.forEach((option) => {
option.classList.toggle('is-visible', option === visibleOption);
});
}
function setOptionAccessibility(group) {
getOptions(group).forEach((option) => {
option.removeAttribute('aria-hidden');
});
}
function setAccessibilityState(group) {
const options = group.querySelector(optionsSelector);
const status = group.querySelector(statusSelector);
const isExpanded = !collapsedLayout.matches || group.classList.contains('is-expanded');
if (options) {
options.setAttribute('aria-expanded', isExpanded ? 'true' : 'false');
}
if (!status) {
return;
}
if (!collapsedLayout.matches) {
status.textContent = '';
return;
}
if (isExpanded) {
status.textContent = 'Alla alternativ visas.';
return;
}
const visibleOption = getVisibleOption(getOptions(group));
const label = visibleOption ? getOptionLabel(visibleOption) : '';
status.textContent = label ? `Valt alternativ: ${label}. Aktivera alternativet för att visa fler alternativ.` : 'Aktivera alternativet för att visa fler alternativ.';
}
function setCollapsedHeight(group) {
const options = group.querySelector(optionsSelector);
if (!options) {
return;
}
group.style.setProperty('--radiobutton-advanced-collapsed-height', `${options.offsetHeight}px`);
}
function collapseGroup(group) {
group.classList.add('is-collapsed');
group.classList.remove('is-expanded');
setVisibleState(group);
setOptionAccessibility(group);
setAccessibilityState(group);
setCollapsedHeight(group);
}
function expandGroup(group) {
group.classList.add('is-expanded');
setOptionAccessibility(group);
setAccessibilityState(group);
}
function syncGroup(group) {
setCheckedState(group);
collapseGroup(group);
}
function syncExpandedGroup(group) {
setCheckedState(group);
setVisibleState(group);
setOptionAccessibility(group);
setAccessibilityState(group);
}
radiobuttonAdvancedGroups.forEach((group) => {
group.addEventListener('pointerdown', () => {
keyboardInteractionGroups.delete(group);
});
group.addEventListener('click', (event) => {
if (!collapsedLayout.matches) {
return;
}
if (keyboardInteractionGroups.has(group)) {
return;
}
const option = event.target.closest(optionSelector);
if (!option || !group.contains(option)) {
return;
}
const input = getInput(option);
if (!input || input.disabled) {
return;
}
if (group.classList.contains('is-expanded')) {
if (option.classList.contains('is-checked')) {
collapseGroup(group);
}
return;
}
if (option.classList.contains('is-visible')) {
event.preventDefault();
expandGroup(group);
}
});
group.addEventListener('keydown', (event) => {
if (!collapsedLayout.matches) {
return;
}
const option = event.target.closest(optionSelector);
if (option && group.contains(option) && keyboardSelectionKeys.includes(event.key)) {
keyboardInteractionGroups.add(group);
}
if (event.key === 'Escape' && group.classList.contains('is-expanded')) {
event.preventDefault();
keyboardInteractionGroups.delete(group);
collapseGroup(group);
const visibleOption = getVisibleOption(getOptions(group));
const input = visibleOption ? getInput(visibleOption) : null;
if (input) {
input.focus();
}
return;
}
if (event.key === 'Enter' && group.classList.contains('is-expanded')) {
event.preventDefault();
keyboardInteractionGroups.delete(group);
collapseGroup(group);
const visibleOption = getVisibleOption(getOptions(group));
const input = visibleOption ? getInput(visibleOption) : null;
if (input) {
input.focus();
}
return;
}
if (!keyboardExpandKeys.includes(event.key) || !option || !group.contains(option) || group.classList.contains('is-expanded') || !option.classList.contains('is-visible')) {
return;
}
event.preventDefault();
keyboardInteractionGroups.add(group);
expandGroup(group);
});
group.addEventListener('change', (event) => {
if (!event.target.matches(inputSelector)) {
return;
}
if (collapsedLayout.matches && group.classList.contains('is-expanded') && keyboardInteractionGroups.has(group)) {
syncExpandedGroup(group);
return;
}
keyboardInteractionGroups.delete(group);
syncGroup(group);
});
syncGroup(group);
});
function syncResponsiveAccessibility() {
radiobuttonAdvancedGroups.forEach((group) => {
setOptionAccessibility(group);
setAccessibilityState(group);
setCollapsedHeight(group);
});
}
if (collapsedLayout.addEventListener) {
collapsedLayout.addEventListener('change', syncResponsiveAccessibility);
} else {
collapsedLayout.addListener(syncResponsiveAccessibility);
}
No notes defined.