Security News
The Risks of Misguided Research in Supply Chain Security
Snyk's use of malicious npm packages for research raises ethical concerns, highlighting risks in public deployment, data exfiltration, and unauthorized testing.
@nrk/core-toggle
Advanced tools
> `@nrk/core-toggle` makes a `` toggle the visibility of next element sibling. Toggles can be nested and easily extended with custom animations or behavior through the [toggle event](#events).
@nrk/core-toggle
makes a<button>
toggle the visibility of next element sibling. Toggles can be nested and easily extended with custom animations or behavior through the toggle event.
<!--demo-->
<button>Popup VanillaJS</button>
<core-toggle class="my-dropdown" popup hidden>
<ul>
<li><a>Link</a></li>
<li>
<button>Can also be nested</button>
<core-toggle class="my-dropdown" popup hidden>
<ul>
<li><a>Sub-link</a></li>
<li><input type="text" autofocus aria-label="Skriv her"></li>
</ul>
</core-toggle>
</li>
</ul>
</core-toggle>
<!--demo-->
<div id="jsx-toggle-popup"></div>
<script type="text/jsx">
ReactDOM.render(<>
<button>Popup JSX</button>
<CoreToggle className='my-dropdown' hidden popup onToggleSelect={console.warn}>
<ul>
<li><button>Select</button></li>
<li><a href='#'>Link</a></li>
<li>
<button>Can also be nested</button>
<CoreToggle className='my-dropdown' hidden popup>
<ul>
<li><a href='#'>Sub-link</a></li>
</ul>
</CoreToggle>
</li>
</ul>
</CoreToggle>
</>, document.getElementById('jsx-toggle-popup'))
</script>
Using NPM provides own element namespace and extensibility. Recommended:
npm install @nrk/core-toggle # Using NPM
Using static registers the custom element with default name automatically:
<script src="https://static.nrk.no/core-components/major/7/core-toggle/core-toggle.min.js"></script> <!-- Using static -->
<button>Toggle VanillaJS</button> <!-- Must be <button> placed directly before <core-toggle> or use id + for attributes -->
<core-toggle
hidden <!-- Set hidden attribute to prevent FOUC -->
popup="{Boolean|String}"> <!-- Optional. Defaults to false. Enable or disable if clicking outside toggle should close it. Provide a string to control the aria-label text on the toggle -->
<div>Content</div>
</core-toggle>
import CoreToggle from '@nrk/core-toggle' // Using NPM
window.customElements.define('core-toggle', CoreToggle) // Using NPM. Replace 'core-toggle' with 'my-toggle' to namespace
const myToggle = document.querySelector('core-toggle')
// Getters
myToggle.button // Get toggle button element
myToggle.popup // Get popup value
myToggle.hidden // Get hidden value
myToggle.value // Get toggle button text
// Setters
myToggle.popup = true // Enable or disable if clicking outside toggle should close it. Provide a string to control the aria-label text on the toggle
myToggle.hidden = true // Set hidden attribute
myToggle.value = 'Velg' // Sets innerHTML of the button and safely updates aria-label for screen readers. Defaults to button.innerHTML
import CoreToggle from '@nrk/core-toggle/jsx'
<CoreToggle
hidden // Set hidden attribute to prevent FOUC
popup={Boolean|String} // Optional. Defaults to false. Enable or disable if clicking outside toggle should close it. Provide a string to control the aria-label text on the toggle
onToggle={Function} // Optional. Toggle event listener. See event 'toggle'
onToggleSelect={Function}> // Optional. Toggle select event listener. See event 'toggle.select'
<button>Use with JSX</button> // First element must result in a <button>. Accepts both elements and components
<div>Content</div> // Next element will be toggled. Accepts both elements and components
</CoreToggle>
Putting the toggle button directly before the content is highly recommended, as this fulfills all accessibility requirements by default. There might be scenarios though, where styling makes this DOM structure impractical. In such cases, give the <button>
a for
attribute, and the <core-toggle>
an id
with corresponding value. Make sure there is no text between the button and toggle content, as this will break the experience for screen reader users:
<div>
<button for="my-toggle">Toggle VanillaJS</button>
</div>
<core-toggle id="my-toggle" hidden>Content</core-toggle>
If you have form elements inside a <core-toggle>
, you can optionally add a autofocus
attribute to the most prominent form element. This helps the user navigate quickly when toggle is opened.
Fired after open state changes:
document.addEventListener('toggle', (event) => {
event.target // The toggle element
})
Fired whenever an <a>
or <button>
element is selected inside a toggle with the popup
option enabled.
Useful for setting the value of the toggle button with the selected value.
document.addEventListener('toggle.select', (event) => {
event.target // The toggle element
event.detail // The selected element
event.target.value = event.detail // Example: set value of toggle to selected element
})
Note: <core-toggle>
is display: inline
by default. Change this by for instance setting core-tabs:not([hidden]) { display: block | flex | grid }
or similar in your app. Not needed when position
or float
is used. All styling in documentation is example only. Both the <button>
and <core-toggle>
element receive attributes reflecting the current toggle state:
.my-button {} /* Target button in any state */
.my-button[aria-expanded="true"] {} /* Target only open button */
.my-button[aria-expanded="false"] {} /* Target only closed button */
.my-toggle-content {} /* Target content in any state */
.my-toggle-content:not([hidden]) {} /* Target only open content */
.my-toggle-content[hidden] {} /* Target only closed content */
Content is only toggled when clicking the button. Great for accordions and expand/collapse panels.
<!--demo-->
<button>Toggle VanillaJS</button> <!-- must be <button> -->
<core-toggle hidden>Content</core-toggle> <!-- hidden prevents flash of unstyled content -->
<!--demo-->
<div id="jsx-toggle-default"></div>
<script type="text/jsx">
ReactDOM.render(<>
<button>Toggle JSX</button>
<CoreToggle hidden onToggle={console.log}>Content</CoreToggle>
</>, document.getElementById('jsx-toggle-default'))
</script>
Listen to the toggle.select
event and update the button's value from the selected item
to create a component that behaves like a <select>
:
<!--demo-->
<button>Episode 1</button>
<core-toggle class="my-select my-dropdown" hidden popup="Choose episode">
<ul>
<li><button>Episode 1</button></li>
<li><button>Episode 2</button></li>
<li><button>Episode 3</button></li>
</ul>
</core-toggle>
<script>
document.addEventListener('toggle.select', (event) => {
if (!event.target.classList.contains('my-select')) return
event.target.value = event.detail
event.target.hidden = true
event.target.button.focus()
})
</script>
<!--demo-->
<div id="jsx-toggle-select"></div>
<script type="text/jsx">
class MyToggleSelect extends React.Component {
constructor (props) {
super(props)
this.state = { value: 'Select number' }
this.onSelect = this.onSelect.bind(this)
}
onSelect (event) {
event.target.hidden = true
this.setState({ value: event.detail.textContent })
}
render () {
return <>
<button>{this.state.value}</button>
<CoreToggle className='my-dropdown' popup='Example picker' hidden onToggleSelect={this.onSelect}>
<ul>
<li><button>One</button></li>
<li><button>Two</button></li>
<li><button>Three</button></li>
</ul>
</CoreToggle>
</>
}
}
ReactDOM.render(<MyToggleSelect/>, document.getElementById('jsx-toggle-select'))
</script>
<details>
instead?Despite having a native <details>
element for expanding/collapsing content, there are several issues regarding browser support, styling, accessibility. Furthermore, polyfills often conflict with other standards such as <dialog>
.
role="menu"
in dropdowns?The menu role is mainly inteded for context menues and toolbars in application interfaces, and has quite complex keyboard navigation requirements. As most end users will not expect application behavior in websites and internal web based systems, (implemented) attributes like aria-controls
and aria-labelledby
is sufficient for a good user experience.
Both touch devices and screen readers will have trouble properly interacting with hoverable interfaces (unless more complex fallback logic is implemented). To achieve a consistent and accessible interface, <core-toggle>
is designed around click interactions.
Some expand/collapse interfaces like accordions behaves like a group - allowing only one expanded area at the time. This pattern however requires more logic and carefully designed animations to avoid confusion over expected scroll position.
Example: The user first opens "Toggle-1", and then "Toggle-2" (which closes "Toggle-1"). Since "Toggle-1" is placed above, the position "Toggle-2" now changes - potentially outside the viewport on smaller devices. Note: If you do need to implement grouping, you can achieve this by reacting to the toggle event.
FAQs
> `@nrk/core-toggle` makes a `` toggle the visibility of next element sibling. Toggles can be nested and easily extended with custom animations or behavior through the [toggle event](#events).
The npm package @nrk/core-toggle receives a total of 739 weekly downloads. As such, @nrk/core-toggle popularity was classified as not popular.
We found that @nrk/core-toggle demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 150 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Snyk's use of malicious npm packages for research raises ethical concerns, highlighting risks in public deployment, data exfiltration, and unauthorized testing.
Research
Security News
Socket researchers found several malicious npm packages typosquatting Chalk and Chokidar, targeting Node.js developers with kill switches and data theft.
Security News
pnpm 10 blocks lifecycle scripts by default to improve security, addressing supply chain attack risks but sparking debate over compatibility and workflow changes.