Accordion Component
To create an accordion component, you can use any HTML element such as div
or section
tag. However, it is recommended to use the div
element for content sections and the button
tag for toggling the visibility of the content. Both elements can be easily styled with CSS
or Tailwind CSS
.
In this example, we will create a reusable accordion component. The accordion component can be customized with different styles and attributes. Here is an example of how to define the accordion component:
To get started, create a new file at src/app/Lib/PHPX/Components/Accordion.php
and add the following code snippet:
It is important to note that you can have one initializer file for all your components. For example, you can follow a naming convention like Accordion
for the main component. The related components should follow the same naming convention, such as AccordionItem
, AccordionTrigger
, and AccordionContent
. These classes should be in the same file and start with the main component name, in this case, Accordion
, followed by the specific component name.
The accordion component will accept the following attributes, along with any other attributes you wish to pass:
class
: Custom CSS classes for additional styling.children
: Content to be rendered within the component.
Note: You can pass any attributes to customize the accordion component further. For example, you can add class
for additional styling.
Execution order of components starts from the innermost child to the outermost parent. The parent component is executed last. This is crucial when dealing with dynamic classes or attributes that rely on the parent component's properties. For instance, if you need to assign a dynamic ID to a specific child, it's important to understand where and how to set special attributes to ensure they receive the correct values.
<Accordion>
<AccordionItem>
<AccordionTrigger>Prisma PHP is awesome!</AccordionTrigger>
<AccordionContent>Prisma PHPX is inspired by JSX and React.</AccordionContent>
</AccordionItem>
</Accordion>
When the above code is executed, the components will be initialized in the following order, starting from the innermost child to the outermost parent: AccordionTrigger
, AccordionContent
, AccordionItem
, and finally Accordion
. If you need to execute the parent component first, you can use the static method init()
. However, keep in mind that static methods are executed only once.
- AccordionTrigger initialized
- AccordionContent initialized
- AccordionItem initialized
- Accordion initialized
You can inject your custom JavaScript into the footer of the page by using the following code. Typically, this is done within the constructor of your class. Use MainLayout::addFooterScript($accordionScript);
to add the script to the footer. The MainLayout
class provides a convenient way to inject scripts into the footer of the page.
public function __construct(array $props = [])
{
parent::__construct($props);
$accordionScript = <<<HTML
<script>
function toggleAccordion(id) {
const allContents = document.querySelectorAll('[id^="content-"]');
const allIcons = document.querySelectorAll('[id^="icon-"]');
const allButtons = document.querySelectorAll('button[aria-expanded]');
// Close all other accordion items
allContents.forEach((content) => {
if (content.id !== 'content-' + id) {
content.classList.add('hidden');
}
});
allIcons.forEach((icon) => {
if (icon.id !== 'icon-' + id) {
icon.classList.remove('rotate-180');
}
});
allButtons.forEach((button) => {
if (button.getAttribute('aria-controls') !== 'content-' + id) {
button.setAttribute('aria-expanded', 'false');
}
});
// Toggle the selected accordion item
const content = document.getElementById('content-' + id);
const icon = document.getElementById('icon-' + id);
const isExpanded = content.classList.contains('hidden');
content.classList.toggle('hidden', !isExpanded);
icon.classList.toggle('rotate-180', isExpanded);
// Update aria-expanded for the clicked button
const button = document.querySelector('[aria-controls="content-' + id + '"]');
button.setAttribute('aria-expanded', isExpanded.toString());
}
</script>
HTML;
MainLayout::addFooterScript($accordionScript);
}
The following code snippet demonstrates how to create an Accordion component in Prisma PHPX, including all related components in a single file:
<?php
namespace Lib\PHPX\Components;
use Lib\MainLayout;
use Lib\PHPX\PHPX;
use Lib\StateManager;
class Accordion extends PHPX
{
public function __construct(array $props = [])
{
parent::__construct($props);
$accordionScript = <<<HTML
<script>
function toggleAccordion(id) {
const allContents = document.querySelectorAll('[id^="content-"]');
const allIcons = document.querySelectorAll('[id^="icon-"]');
const allButtons = document.querySelectorAll('button[aria-expanded]');
// Close all other accordion items
allContents.forEach((content) => {
if (content.id !== 'content-' + id) {
content.classList.add('hidden');
}
});
allIcons.forEach((icon) => {
if (icon.id !== 'icon-' + id) {
icon.classList.remove('rotate-180');
}
});
allButtons.forEach((button) => {
if (button.getAttribute('aria-controls') !== 'content-' + id) {
button.setAttribute('aria-expanded', 'false');
}
});
// Toggle the selected accordion item
const content = document.getElementById('content-' + id);
const icon = document.getElementById('icon-' + id);
const isExpanded = content.classList.contains('hidden');
content.classList.toggle('hidden', !isExpanded);
icon.classList.toggle('rotate-180', isExpanded);
// Update aria-expanded for the clicked button
const button = document.querySelector('[aria-controls="content-' + id + '"]');
button.setAttribute('aria-expanded', isExpanded.toString());
}
</script>
HTML;
MainLayout::addFooterScript($accordionScript);
}
public function render(): string
{
$attributes = $this->getAttributes();
$class = $this->getMergeClasses('accordion w-full max-w-md mx-auto');
return <<<HTML
<div class="$class" $attributes>{$this->children}</div>
HTML;
}
}
class AccordionItem extends PHPX
{
public function __construct(array $props = [])
{
parent::__construct($props);
}
public function render(): string
{
$attributes = $this->getAttributes();
$class = $this->getMergeClasses('border-b');
return <<<HTML
<div class="$class" $attributes>{$this->children}</div>
HTML;
}
}
class AccordionTrigger extends PHPX
{
public function __construct(array $props = [])
{
parent::__construct($props);
StateManager::setState('accordionItemId', uniqid());
}
public function render(): string
{
$accordionItemId = StateManager::getState('accordionItemId');
$attributes = $this->getAttributes([
'aria-expanded' => 'false',
'aria-controls' => 'content-' . $accordionItemId,
'id' => $accordionItemId,
'type' => 'button',
]);
$class = $this->getMergeClasses('flex justify-between items-center w-full py-3 px-4 text-left text-gray-800 focus:outline-none');
return <<<HTML
<button class="$class" $attributes onclick="toggleAccordion('$accordionItemId')">
{$this->children}
<svg id="icon-$accordionItemId" class="w-5 h-5 text-gray-600 transition-transform transform rotate-0" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</button>
HTML;
}
}
class AccordionContent extends PHPX
{
public function __construct(array $props = [])
{
parent::__construct($props);
}
public function render(): string
{
$accordionItemId = StateManager::getState('accordionItemId');
$attributes = $this->getAttributes([
'aria-labelledby' => $accordionItemId,
'id' => 'content-' . $accordionItemId,
'role' => 'region',
]);
$class = $this->getMergeClasses('hidden px-4 py-2 text-gray-700');
return <<<HTML
<div class="$class" $attributes>
{$this->children}
</div>
HTML;
}
}
Now, you can integrate the Accordion
component into your Prisma PHP application by following the example below:
<?php
use Lib\PHPX\Components\{Accordion, AccordionItem, AccordionTrigger, AccordionContent};
?>
<Accordion>
<AccordionItem class="bg-green-500">
<AccordionTrigger>Is it accessible?</AccordionTrigger>
<AccordionContent>Yes. It adheres to the WAI-ARIA design pattern.</AccordionContent>
</AccordionItem>
<AccordionItem>
<AccordionTrigger>Is it styled?</AccordionTrigger>
<AccordionContent>Yes. It comes with default styles that match the other components' aesthetic.</AccordionContent>
</AccordionItem>
<AccordionItem>
<AccordionTrigger>Is it animated?</AccordionTrigger>
<AccordionContent>Yes. It includes smooth animations.</AccordionContent>
</AccordionItem>
</Accordion>
By following the steps above, you have successfully created a reusable Accordion
component using Prisma PHPX. You can now use this component in your application to display accordion items with various styles and behaviors.
In the render
method, we use the div
and button
tags to render the accordion and its items. You can customize the accordion by passing different props such as class
to achieve the desired look and feel.